-
Notifications
You must be signed in to change notification settings - Fork 15
/
BaseBranchRouter.sol
218 lines (182 loc) · 7.57 KB
/
BaseBranchRouter.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Ownable} from "solady/auth/Ownable.sol";
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {ERC20} from "solmate/tokens/ERC20.sol";
import {IBranchRouter} from "./interfaces/IBranchRouter.sol";
import {
IBranchBridgeAgent as IBridgeAgent,
GasParams,
Deposit,
DepositInput,
DepositParams,
DepositMultipleInput,
DepositMultipleParams,
SettlementParams,
SettlementMultipleParams
} from "./interfaces/IBranchBridgeAgent.sol";
/// @title Base Branch Router Contract
/// @author MaiaDAO
contract BaseBranchRouter is IBranchRouter, Ownable {
using SafeTransferLib for address;
/*///////////////////////////////////////////////////////////////
BASE BRANCH ROUTER STATE
//////////////////////////////////////////////////////////////*/
/// @inheritdoc IBranchRouter
address public localPortAddress;
/// @inheritdoc IBranchRouter
address public override localBridgeAgentAddress;
/// @inheritdoc IBranchRouter
address public override bridgeAgentExecutorAddress;
/// @notice Re-entrancy lock modifier state.
uint256 internal _unlocked = 1;
/*///////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor() {
_initializeOwner(msg.sender);
}
/*///////////////////////////////////////////////////////////////
INITIALIZATION FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Initializes the Base Branch Router.
* @param _localBridgeAgentAddress The address of the local Bridge Agent.
*/
function initialize(address _localBridgeAgentAddress) external onlyOwner {
require(_localBridgeAgentAddress != address(0), "Bridge Agent address cannot be 0");
localBridgeAgentAddress = _localBridgeAgentAddress;
localPortAddress = IBridgeAgent(_localBridgeAgentAddress).localPortAddress();
bridgeAgentExecutorAddress = IBridgeAgent(_localBridgeAgentAddress).bridgeAgentExecutorAddress();
renounceOwnership();
}
/*///////////////////////////////////////////////////////////////
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @inheritdoc IBranchRouter
function getDepositEntry(uint32 _depositNonce) external view override returns (Deposit memory) {
return IBridgeAgent(localBridgeAgentAddress).getDepositEntry(_depositNonce);
}
/*///////////////////////////////////////////////////////////////
EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @inheritdoc IBranchRouter
function callOut(bytes calldata _params, GasParams calldata _gParams) external payable override lock {
IBridgeAgent(localBridgeAgentAddress).callOut{value: msg.value}(payable(msg.sender), _params, _gParams);
}
/// @inheritdoc IBranchRouter
function callOutAndBridge(bytes calldata _params, DepositInput calldata _dParams, GasParams calldata _gParams)
external
payable
override
lock
{
//Transfer tokens to this contract.
_transferAndApproveToken(_dParams.hToken, _dParams.token, _dParams.amount, _dParams.deposit);
//Perform call to bridge agent.
IBridgeAgent(localBridgeAgentAddress).callOutAndBridge{value: msg.value}(
payable(msg.sender), _params, _dParams, _gParams
);
}
/// @inheritdoc IBranchRouter
function callOutAndBridgeMultiple(
bytes calldata _params,
DepositMultipleInput calldata _dParams,
GasParams calldata _gParams
) external payable override lock {
//Transfer tokens to this contract.
_transferAndApproveMultipleTokens(_dParams.hTokens, _dParams.tokens, _dParams.amounts, _dParams.deposits);
//Perform call to bridge agent.
IBridgeAgent(localBridgeAgentAddress).callOutAndBridgeMultiple{value: msg.value}(
payable(msg.sender), _params, _dParams, _gParams
);
}
/*///////////////////////////////////////////////////////////////
BRIDGE AGENT EXECUTOR EXTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/// @inheritdoc IBranchRouter
function executeNoSettlement(bytes calldata) external payable virtual override requiresAgentExecutor {
revert UnrecognizedFunctionId();
}
/// @inheritdoc IBranchRouter
function executeSettlement(bytes calldata, SettlementParams memory)
external
payable
virtual
override
requiresAgentExecutor
{
revert UnrecognizedFunctionId();
}
/// @inheritdoc IBranchRouter
function executeSettlementMultiple(bytes calldata, SettlementMultipleParams memory)
external
payable
virtual
override
requiresAgentExecutor
{
revert UnrecognizedFunctionId();
}
/*///////////////////////////////////////////////////////////////
INTERNAL FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Internal function to transfer token into a contract.
* @param _hToken The address of the hToken.
* @param _token The address of the token.
* @param _amount The amount of the hToken.
* @param _deposit The amount of the token.
*/
function _transferAndApproveToken(address _hToken, address _token, uint256 _amount, uint256 _deposit) internal {
// Cache local port address
address _localPortAddress = localPortAddress;
// Check if the local branch tokens are being spent
if (_amount - _deposit > 0) {
unchecked {
_hToken.safeTransferFrom(msg.sender, address(this), _amount - _deposit);
ERC20(_hToken).approve(_localPortAddress, _amount - _deposit);
}
}
// Check if the underlying tokens are being spent
if (_deposit > 0) {
_token.safeTransferFrom(msg.sender, address(this), _deposit);
ERC20(_token).approve(_localPortAddress, _deposit);
}
}
/**
* @notice Internal function to transfer multiple tokens into a contract.
* @param _hTokens The addresses of the hTokens.
* @param _tokens The addresses of the tokens.
* @param _amounts The amounts of the hTokens.
* @param _deposits The amounts of the tokens.
*/
function _transferAndApproveMultipleTokens(
address[] memory _hTokens,
address[] memory _tokens,
uint256[] memory _amounts,
uint256[] memory _deposits
) internal {
for (uint256 i = 0; i < _hTokens.length;) {
_transferAndApproveToken(_hTokens[i], _tokens[i], _amounts[i], _deposits[i]);
unchecked {
++i;
}
}
}
/*///////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/// @notice Modifier that verifies msg sender is the Bridge Agent Executor.
modifier requiresAgentExecutor() {
if (msg.sender != bridgeAgentExecutorAddress) revert UnrecognizedBridgeAgentExecutor();
_;
}
/// @notice Modifier for a simple re-entrancy check.
modifier lock() {
require(_unlocked == 1);
_unlocked = 2;
_;
_unlocked = 1;
}
}