Skip to content

Commit bd13bf5

Browse files
perf: Bridge upgrade (#212)
* first batch of test done * update final hash of vaultManager implementation * feat: solidity implementation for upgraded bridge system * feat: add tests for the new use cases * add deployment scripts * change min gas * continuing deployment script * feat: deployment of the contract on multiple different chains * feat: deploy new swapper contract * remove adapter contracts --------- Co-authored-by: gs8nrv <[email protected]>
1 parent accf768 commit bd13bf5

30 files changed

+18279
-334
lines changed

contracts/agToken/layerZero/utils/NonblockingLzApp.sol

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ abstract contract NonblockingLzApp is Initializable, ILayerZeroReceiver, ILayerZ
2424
/// @notice Reference to the treasury contract to fetch access control
2525
address public treasury;
2626

27+
/// @notice Maps pairs of (`to` chain, `packetType`) to the minimum amount of gas needed on the destination chain
28+
mapping(uint16 => mapping(uint16 => uint256)) public minDstGasLookup;
29+
30+
/// @notice For future LayerZero compatibility
31+
address public precrime;
32+
2733
// ================================== Events ===================================
2834

2935
event SetTrustedRemote(uint16 _srcChainId, bytes _srcAddress);
@@ -33,9 +39,11 @@ abstract contract NonblockingLzApp is Initializable, ILayerZeroReceiver, ILayerZ
3339

3440
error NotGovernor();
3541
error NotGovernorOrGuardian();
42+
error InsufficientGas();
3643
error InvalidEndpoint();
3744
error InvalidSource();
3845
error InvalidCaller();
46+
error InvalidParams();
3947
error InvalidPayload();
4048
error ZeroAddress();
4149

@@ -178,6 +186,26 @@ abstract contract NonblockingLzApp is Initializable, ILayerZeroReceiver, ILayerZ
178186
);
179187
}
180188

189+
/// @notice Checks the gas limit of a given transaction
190+
function _checkGasLimit(
191+
uint16 _dstChainId,
192+
uint16 _type,
193+
bytes memory _adapterParams,
194+
uint256 _extraGas
195+
) internal view virtual {
196+
uint256 minGasLimit = minDstGasLookup[_dstChainId][_type] + _extraGas;
197+
if (minGasLimit == 0 || minGasLimit > _getGasLimit(_adapterParams)) revert InsufficientGas();
198+
}
199+
200+
/// @notice Gets the gas limit from the `_adapterParams` parameter
201+
function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint256 gasLimit) {
202+
if (_adapterParams.length < 34) revert InvalidParams();
203+
// solhint-disable-next-line
204+
assembly {
205+
gasLimit := mload(add(_adapterParams, 34))
206+
}
207+
}
208+
181209
// ======================= Governance Functions ================================
182210

183211
/// @notice Sets the corresponding address on an other chain.
@@ -222,14 +250,24 @@ abstract contract NonblockingLzApp is Initializable, ILayerZeroReceiver, ILayerZ
222250
}
223251

224252
/// @notice Unpauses the receive functionalities
225-
function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress)
226-
external
227-
override
228-
onlyGovernorOrGuardian
229-
{
253+
function forceResumeReceive(
254+
uint16 _srcChainId,
255+
bytes calldata _srcAddress
256+
) external override onlyGovernorOrGuardian {
230257
lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);
231258
}
232259

260+
/// @notice Sets the minimum gas parameter for a packet type on a given chain
261+
function setMinDstGas(uint16 _dstChainId, uint16 _packetType, uint256 _minGas) external onlyGovernorOrGuardian {
262+
if (_minGas == 0) revert InvalidParams();
263+
minDstGasLookup[_dstChainId][_packetType] = _minGas;
264+
}
265+
266+
/// @notice Sets the precrime variable
267+
function setPrecrime(address _precrime) external onlyGovernorOrGuardian {
268+
precrime = _precrime;
269+
}
270+
233271
// ======================= View Functions ================================
234272

235273
/// @notice Checks if the `_srcAddress` corresponds to the trusted source
@@ -238,5 +276,5 @@ abstract contract NonblockingLzApp is Initializable, ILayerZeroReceiver, ILayerZ
238276
return keccak256(trustedSource) == keccak256(_srcAddress);
239277
}
240278

241-
uint256[46] private __gap;
279+
uint256[44] private __gap;
242280
}

contracts/agToken/layerZero/utils/OFTCore.sol

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeabl
1111
/// but with slight modifications from the Angle Labs, Inc. which added return values to the `_creditTo` and `_debitFrom` functions
1212
/// @notice Base contract for bridging using LayerZero
1313
abstract contract OFTCore is NonblockingLzApp, ERC165Upgradeable, IOFTCore {
14+
/// @notice Amount of additional gas specified
15+
uint256 public constant EXTRA_GAS = 200000;
16+
/// @notice Packet type for token transfer
17+
uint16 public constant PT_SEND = 0;
18+
19+
/// @notice Whether to use custom parameters in transactions
20+
uint8 public useCustomAdapterParams;
21+
1422
// ==================== External Permissionless Functions ======================
1523

1624
/// @inheritdoc IOFTCore
@@ -36,6 +44,7 @@ abstract contract OFTCore is NonblockingLzApp, ERC165Upgradeable, IOFTCore {
3644
address _zroPaymentAddress,
3745
bytes memory _adapterParams
3846
) public payable virtual {
47+
_checkAdapterParams(_dstChainId, PT_SEND, _adapterParams, EXTRA_GAS);
3948
_amount = _debitFrom(_dstChainId, _toAddress, _amount);
4049

4150
bytes memory payload = abi.encode(_toAddress, _amount);
@@ -54,6 +63,7 @@ abstract contract OFTCore is NonblockingLzApp, ERC165Upgradeable, IOFTCore {
5463
address _zroPaymentAddress,
5564
bytes memory _adapterParams
5665
) public payable virtual {
66+
_checkAdapterParams(_dstChainId, PT_SEND, _adapterParams, EXTRA_GAS);
5767
_amount = _debitCreditFrom(_dstChainId, _toAddress, _amount);
5868

5969
_send(_dstChainId, _toAddress, _amount, _refundAddress, _zroPaymentAddress, _adapterParams);
@@ -62,6 +72,11 @@ abstract contract OFTCore is NonblockingLzApp, ERC165Upgradeable, IOFTCore {
6272
/// @inheritdoc IOFTCore
6373
function withdraw(uint256 amount, address recipient) external virtual returns (uint256);
6474

75+
/// @notice Sets whether custom adapter parameters can be used or not
76+
function setUseCustomAdapterParams(uint8 _useCustomAdapterParams) public virtual onlyGovernorOrGuardian {
77+
useCustomAdapterParams = _useCustomAdapterParams;
78+
}
79+
6580
// =========================== Internal Functions ==============================
6681

6782
/// @notice Internal function to send `_amount` amount of token to (`_dstChainId`, `_toAddress`)
@@ -106,6 +121,17 @@ abstract contract OFTCore is NonblockingLzApp, ERC165Upgradeable, IOFTCore {
106121
emit ReceiveFromChain(_srcChainId, _srcAddress, toAddress, amount, _nonce);
107122
}
108123

124+
/// @notice Checks the adapter parameters given during the smart contract call
125+
function _checkAdapterParams(
126+
uint16 _dstChainId,
127+
uint16 _pkType,
128+
bytes memory _adapterParams,
129+
uint256 _extraGas
130+
) internal virtual {
131+
if (useCustomAdapterParams > 0) _checkGasLimit(_dstChainId, _pkType, _adapterParams, _extraGas);
132+
else if (_adapterParams.length != 0) revert InvalidParams();
133+
}
134+
109135
/// @notice Makes accountability when bridging from this contract using canonical token
110136
/// @param _dstChainId ChainId of the destination chain - LayerZero standard
111137
/// @param _toAddress Recipient on the destination chain
@@ -130,22 +156,14 @@ abstract contract OFTCore is NonblockingLzApp, ERC165Upgradeable, IOFTCore {
130156
/// @param _srcChainId ChainId of the source chain - LayerZero standard
131157
/// @param _toAddress Recipient on this chain
132158
/// @param _amount Amount to bridge
133-
function _creditTo(
134-
uint16 _srcChainId,
135-
address _toAddress,
136-
uint256 _amount
137-
) internal virtual returns (uint256);
159+
function _creditTo(uint16 _srcChainId, address _toAddress, uint256 _amount) internal virtual returns (uint256);
138160

139161
// ========================== View Functions ===================================
140162

141163
/// @inheritdoc ERC165Upgradeable
142-
function supportsInterface(bytes4 interfaceId)
143-
public
144-
view
145-
virtual
146-
override(ERC165Upgradeable, IERC165)
147-
returns (bool)
148-
{
164+
function supportsInterface(
165+
bytes4 interfaceId
166+
) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
149167
return interfaceId == type(IOFTCore).interfaceId || super.supportsInterface(interfaceId);
150168
}
151169

@@ -162,5 +180,5 @@ abstract contract OFTCore is NonblockingLzApp, ERC165Upgradeable, IOFTCore {
162180
return lzEndpoint.estimateFees(_dstChainId, address(this), payload, _useZro, _adapterParams);
163181
}
164182

165-
uint256[50] private __gap;
183+
uint256[49] private __gap;
166184
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.12;
4+
5+
import "./OldOFTCore.sol";
6+
import "../../interfaces/IAgTokenSideChainMultiBridge.sol";
7+
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
8+
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
9+
10+
/// @title LayerZeroBridgeToken
11+
/// @author Angle Labs, Inc., forked from https://github.com/LayerZero-Labs/solidity-examples/blob/main/contracts/token/oft/OFT.sol
12+
/// @notice Contract to be deployed on a L2/sidechain for bridging an AgToken using a bridge intermediate token and LayerZero
13+
contract OldLayerZeroBridgeToken is OldOFTCore, ERC20Upgradeable, PausableUpgradeable {
14+
/// @notice Address of the bridgeable token
15+
/// @dev Immutable
16+
IAgTokenSideChainMultiBridge public canonicalToken;
17+
18+
// =============================== Errors ================================
19+
20+
error InvalidAllowance();
21+
22+
// ============================= Constructor ===================================
23+
24+
/// @notice Initializes the contract
25+
/// @param _name Name of the token corresponding to this contract
26+
/// @param _symbol Symbol of the token corresponding to this contract
27+
/// @param _lzEndpoint Layer zero endpoint to pass messages
28+
/// @param _treasury Address of the treasury contract used for access control
29+
/// @param initialSupply Initial supply to mint to the canonical token address
30+
/// @dev The initial supply corresponds to the initial amount that could be bridged using this OFT
31+
function initialize(
32+
string memory _name,
33+
string memory _symbol,
34+
address _lzEndpoint,
35+
address _treasury,
36+
uint256 initialSupply
37+
) external initializer {
38+
__ERC20_init_unchained(_name, _symbol);
39+
__LzAppUpgradeable_init(_lzEndpoint, _treasury);
40+
41+
canonicalToken = IAgTokenSideChainMultiBridge(address(ITreasury(_treasury).stablecoin()));
42+
_approve(address(this), address(canonicalToken), type(uint256).max);
43+
_mint(address(canonicalToken), initialSupply);
44+
}
45+
46+
/// @custom:oz-upgrades-unsafe-allow constructor
47+
constructor() initializer {}
48+
49+
// ==================== External Permissionless Functions ======================
50+
51+
function sendWithPermit(
52+
uint16 _dstChainId,
53+
bytes memory _toAddress,
54+
uint256 _amount,
55+
address payable _refundAddress,
56+
address _zroPaymentAddress,
57+
bytes memory _adapterParams,
58+
uint256 deadline,
59+
uint8 v,
60+
bytes32 r,
61+
bytes32 s
62+
) public payable override {
63+
canonicalToken.permit(msg.sender, address(this), _amount, deadline, v, r, s);
64+
send(_dstChainId, _toAddress, _amount, _refundAddress, _zroPaymentAddress, _adapterParams);
65+
}
66+
67+
function withdraw(uint256 amount, address recipient) external override returns (uint256 amountMinted) {
68+
// Does not check allowances as transfers from `msg.sender`
69+
_transfer(msg.sender, address(this), amount);
70+
amountMinted = canonicalToken.swapIn(address(this), amount, recipient);
71+
uint256 leftover = balanceOf(address(this));
72+
if (leftover != 0) {
73+
_transfer(address(this), msg.sender, leftover);
74+
}
75+
}
76+
77+
// ============================= Internal Functions ===================================
78+
79+
function _debitFrom(
80+
uint16,
81+
bytes memory,
82+
uint256 _amount
83+
) internal override whenNotPaused returns (uint256 amountSwapped) {
84+
// No need to use safeTransferFrom as we know this implementation reverts on failure
85+
canonicalToken.transferFrom(msg.sender, address(this), _amount);
86+
87+
// Swap canonical for this bridge token. There may be some fees
88+
amountSwapped = canonicalToken.swapOut(address(this), _amount, address(this));
89+
_burn(address(this), amountSwapped);
90+
}
91+
92+
function _debitCreditFrom(uint16, bytes memory, uint256 _amount) internal override whenNotPaused returns (uint256) {
93+
_burn(msg.sender, _amount);
94+
return _amount;
95+
}
96+
97+
function _creditTo(
98+
uint16,
99+
address _toAddress,
100+
uint256 _amount
101+
) internal override whenNotPaused returns (uint256 amountMinted) {
102+
_mint(address(this), _amount);
103+
amountMinted = canonicalToken.swapIn(address(this), _amount, _toAddress);
104+
uint256 leftover = balanceOf(address(this));
105+
if (leftover != 0) {
106+
_transfer(address(this), _toAddress, leftover);
107+
}
108+
}
109+
110+
// ======================= View Functions ================================
111+
112+
/// @inheritdoc ERC165Upgradeable
113+
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
114+
return
115+
interfaceId == type(IOFT).interfaceId ||
116+
interfaceId == type(IERC20).interfaceId ||
117+
super.supportsInterface(interfaceId);
118+
}
119+
120+
// ======================= Governance Functions ================================
121+
122+
/// @notice Mints the intermediate contract to the `canonicalToken`
123+
/// @dev Used to increase the bridging capacity
124+
function mint(uint256 amount) external onlyGovernorOrGuardian {
125+
_mint(address(canonicalToken), amount);
126+
}
127+
128+
/// @notice Burns the intermediate contract from the `canonicalToken`
129+
/// @dev Used to decrease the bridging capacity
130+
function burn(uint256 amount) external onlyGovernorOrGuardian {
131+
_burn(address(canonicalToken), amount);
132+
}
133+
134+
/// @notice Increases allowance of the `canonicalToken`
135+
function setupAllowance() public onlyGovernorOrGuardian {
136+
_approve(address(this), address(canonicalToken), type(uint256).max);
137+
}
138+
139+
/// @notice Pauses bridging through the contract
140+
/// @param pause Future pause status
141+
function pauseSendTokens(bool pause) external onlyGovernorOrGuardian {
142+
pause ? _pause() : _unpause();
143+
}
144+
145+
uint256[49] private __gap;
146+
}

0 commit comments

Comments
 (0)