From 85ba500ed4c7a0cb5d7b6de39e3dc5b33e0880b6 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 5 Sep 2024 12:25:53 +0530 Subject: [PATCH 1/6] moved solmate to npm dependency --- .gitmodules | 3 --- lib/solmate | 1 - package.json | 3 ++- remappings.txt | 2 +- src/factory/ImmutableMultiChainDeployer.sol | 2 +- yarn.lock | 5 +++++ 6 files changed, 9 insertions(+), 7 deletions(-) delete mode 100644 .gitmodules delete mode 160000 lib/solmate diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 8640357..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "lib/solmate"] - path = lib/solmate - url = https://github.com/transmissions11/solmate diff --git a/lib/solmate b/lib/solmate deleted file mode 160000 index 97bdb20..0000000 --- a/lib/solmate +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 97bdb2003b70382996a79a406813f76417b1cf90 diff --git a/package.json b/package.json index 83a0c0f..26efbbb 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "dependencies": { "@layerzerolabs/lz-evm-v1-0.7": "^2.3.40", "hardhat-deploy": "^0.12.4", - "lint-staged": "^15.2.10" + "lint-staged": "^15.2.10", + "solmate": "^6.2.0" } } diff --git a/remappings.txt b/remappings.txt index e25941b..6db31b8 100644 --- a/remappings.txt +++ b/remappings.txt @@ -8,7 +8,7 @@ forge-std/=node_modules/forge-std/src/ @layerzerolabs/lz-evm-v1-0.7/=node_modules/@layerzerolabs/lz-evm-v1-0.7/ @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ @openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/ -@solmate/=lib/solmate/src/ +@solmate/=node_modules/solmate/src/ @adapters/=src/ @factory/=src/factory/ @interfaces/=src/interfaces/ diff --git a/src/factory/ImmutableMultiChainDeployer.sol b/src/factory/ImmutableMultiChainDeployer.sol index bf7bb84..68fbe4b 100644 --- a/src/factory/ImmutableMultiChainDeployer.sol +++ b/src/factory/ImmutableMultiChainDeployer.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import {CREATE3} from "solmate/utils/CREATE3.sol"; +import {CREATE3} from "@solmate/utils/CREATE3.sol"; import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol"; diff --git a/yarn.lock b/yarn.lock index cfa1caa..a434221 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1201,6 +1201,11 @@ solidity-bytes-utils@^0.8.2: ds-test "github:dapphub/ds-test" forge-std "^1.1.2" +solmate@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/solmate/-/solmate-6.2.0.tgz#edd29b5f3d6faafafdcf65fe4d1d959b4841cfa8" + integrity sha512-AM38ioQ2P8zRsA42zenb9or6OybRjOLXIu3lhIT8rhddUuduCt76pUEuLxOIg9GByGojGz+EbpFdCB6B+QZVVA== + string-argv@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" From 945335c6857cad32e0cb69eda07f412c7829d291 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 5 Sep 2024 12:27:07 +0530 Subject: [PATCH 2/6] removed unnecessary files --- test/interfaces/ILayerZeroEndpoint.sol | 110 ------------------ test/interfaces/ILayerZeroReceiver.sol | 13 --- .../ILayerZeroUserApplicationConfig.sol | 25 ---- test/lib/LzLib.sol | 93 --------------- 4 files changed, 241 deletions(-) delete mode 100644 test/interfaces/ILayerZeroEndpoint.sol delete mode 100644 test/interfaces/ILayerZeroReceiver.sol delete mode 100644 test/interfaces/ILayerZeroUserApplicationConfig.sol delete mode 100644 test/lib/LzLib.sol diff --git a/test/interfaces/ILayerZeroEndpoint.sol b/test/interfaces/ILayerZeroEndpoint.sol deleted file mode 100644 index fe223b0..0000000 --- a/test/interfaces/ILayerZeroEndpoint.sol +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.5.0; - -import "./ILayerZeroUserApplicationConfig.sol"; - -interface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig { - // @notice send a LayerZero message to the specified address at a LayerZero endpoint. - // @param _dstChainId - the destination chain identifier - // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains - // @param _payload - a custom bytes payload to send to the destination contract - // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address - // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction - // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination - function send( - uint16 _dstChainId, - bytes calldata _destination, - bytes calldata _payload, - address payable _refundAddress, - address _zroPaymentAddress, - bytes calldata _adapterParams - ) external payable; - - // @notice used by the messaging library to publish verified payload - // @param _srcChainId - the source chain identifier - // @param _srcAddress - the source contract (as bytes) at the source chain - // @param _dstAddress - the address on destination chain - // @param _nonce - the unbound message ordering nonce - // @param _gasLimit - the gas limit for external contract execution - // @param _payload - verified payload to send to the destination contract - function receivePayload( - uint16 _srcChainId, - bytes calldata _srcAddress, - address _dstAddress, - uint64 _nonce, - uint256 _gasLimit, - bytes calldata _payload - ) external; - - // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain - // @param _srcChainId - the source chain identifier - // @param _srcAddress - the source chain contract address - function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64); - - // @notice get the outboundNonce from this source chain which, consequently, is always an EVM - // @param _srcAddress - the source chain contract address - function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64); - - // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery - // @param _dstChainId - the destination chain identifier - // @param _userApplication - the user app address on this EVM chain - // @param _payload - the custom message to send over LayerZero - // @param _payInZRO - if false, user app pays the protocol fee in native token - // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain - function estimateFees( - uint16 _dstChainId, - address _userApplication, - bytes calldata _payload, - bool _payInZRO, - bytes calldata _adapterParam - ) external view returns (uint256 nativeFee, uint256 zroFee); - - // @notice get this Endpoint's immutable source identifier - function getChainId() external view returns (uint16); - - // @notice the interface to retry failed message on this Endpoint destination - // @param _srcChainId - the source chain identifier - // @param _srcAddress - the source chain contract address - // @param _payload - the payload to be retried - function retryPayload(uint16 _srcChainId, bytes calldata _srcAddress, bytes calldata _payload) external; - - // @notice query if any STORED payload (message blocking) at the endpoint. - // @param _srcChainId - the source chain identifier - // @param _srcAddress - the source chain contract address - function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool); - - // @notice query if the _libraryAddress is valid for sending msgs. - // @param _userApplication - the user app address on this EVM chain - function getSendLibraryAddress(address _userApplication) external view returns (address); - - // @notice query if the _libraryAddress is valid for receiving msgs. - // @param _userApplication - the user app address on this EVM chain - function getReceiveLibraryAddress(address _userApplication) external view returns (address); - - // @notice query if the non-reentrancy guard for send() is on - // @return true if the guard is on. false otherwise - function isSendingPayload() external view returns (bool); - - // @notice query if the non-reentrancy guard for receive() is on - // @return true if the guard is on. false otherwise - function isReceivingPayload() external view returns (bool); - - // @notice get the configuration of the LayerZero messaging library of the specified version - // @param _version - messaging library version - // @param _chainId - the chainId for the pending config change - // @param _userApplication - the contract address of the user application - // @param _configType - type of configuration. every messaging library has its own convention. - function getConfig(uint16 _version, uint16 _chainId, address _userApplication, uint256 _configType) - external - view - returns (bytes memory); - - // @notice get the send() LayerZero messaging library version - // @param _userApplication - the contract address of the user application - function getSendVersion(address _userApplication) external view returns (uint16); - - // @notice get the lzReceive() LayerZero messaging library version - // @param _userApplication - the contract address of the user application - function getReceiveVersion(address _userApplication) external view returns (uint16); -} diff --git a/test/interfaces/ILayerZeroReceiver.sol b/test/interfaces/ILayerZeroReceiver.sol deleted file mode 100644 index d4de8d4..0000000 --- a/test/interfaces/ILayerZeroReceiver.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.5.0; - -interface ILayerZeroReceiver { - // @notice LayerZero endpoint will invoke this function to deliver the message on the destination - // @param _srcChainId - the source endpoint identifier - // @param _srcAddress - the source sending contract address from the source chain - // @param _nonce - the ordered message nonce - // @param _payload - the signed payload is the UA bytes has encoded to be sent - function lzReceive(uint16 _srcChainId, bytes calldata _srcAddress, uint64 _nonce, bytes calldata _payload) - external; -} diff --git a/test/interfaces/ILayerZeroUserApplicationConfig.sol b/test/interfaces/ILayerZeroUserApplicationConfig.sol deleted file mode 100644 index c9f8ab7..0000000 --- a/test/interfaces/ILayerZeroUserApplicationConfig.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity >=0.5.0; - -interface ILayerZeroUserApplicationConfig { - // @notice set the configuration of the LayerZero messaging library of the specified version - // @param _version - messaging library version - // @param _chainId - the chainId for the pending config change - // @param _configType - type of configuration. every messaging library has its own convention. - // @param _config - configuration in the bytes. can encode arbitrary content. - function setConfig(uint16 _version, uint16 _chainId, uint256 _configType, bytes calldata _config) external; - - // @notice set the send() LayerZero messaging library version to _version - // @param _version - new messaging library version - function setSendVersion(uint16 _version) external; - - // @notice set the lzReceive() LayerZero messaging library version to _version - // @param _version - new messaging library version - function setReceiveVersion(uint16 _version) external; - - // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload - // @param _srcChainId - the chainId of the source chain - // @param _srcAddress - the contract address of the source contract at the source chain - function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external; -} diff --git a/test/lib/LzLib.sol b/test/lib/LzLib.sol deleted file mode 100644 index 79308bb..0000000 --- a/test/lib/LzLib.sol +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -pragma solidity >=0.6.0; -pragma experimental ABIEncoderV2; - -library LzLib { - // LayerZero communication - struct CallParams { - address payable refundAddress; - address zroPaymentAddress; - } - - //--------------------------------------------------------------------------- - // Address type handling - - struct AirdropParams { - uint256 airdropAmount; - bytes32 airdropAddress; - } - - function buildAdapterParams(LzLib.AirdropParams memory _airdropParams, uint256 _uaGasLimit) - internal - pure - returns (bytes memory adapterParams) - { - if (_airdropParams.airdropAmount == 0 && _airdropParams.airdropAddress == bytes32(0x0)) { - adapterParams = buildDefaultAdapterParams(_uaGasLimit); - } else { - adapterParams = buildAirdropAdapterParams(_uaGasLimit, _airdropParams); - } - } - - // Build Adapter Params - function buildDefaultAdapterParams(uint256 _uaGas) internal pure returns (bytes memory) { - // txType 1 - // bytes [2 32 ] - // fields [txType extraGas] - return abi.encodePacked(uint16(1), _uaGas); - } - - function buildAirdropAdapterParams(uint256 _uaGas, AirdropParams memory _params) - internal - pure - returns (bytes memory) - { - require(_params.airdropAmount > 0, "Airdrop amount must be greater than 0"); - require(_params.airdropAddress != bytes32(0x0), "Airdrop address must be set"); - - // txType 2 - // bytes [2 32 32 bytes[] ] - // fields [txType extraGas dstNativeAmt dstNativeAddress] - return abi.encodePacked(uint16(2), _uaGas, _params.airdropAmount, _params.airdropAddress); - } - - function getGasLimit(bytes memory _adapterParams) internal pure returns (uint256 gasLimit) { - require(_adapterParams.length == 34 || _adapterParams.length > 66, "Invalid adapterParams"); - assembly { - gasLimit := mload(add(_adapterParams, 34)) - } - } - - // Decode Adapter Params - function decodeAdapterParams(bytes memory _adapterParams) - internal - pure - returns (uint16 txType, uint256 uaGas, uint256 airdropAmount, address payable airdropAddress) - { - require(_adapterParams.length == 34 || _adapterParams.length > 66, "Invalid adapterParams"); - assembly { - txType := mload(add(_adapterParams, 2)) - uaGas := mload(add(_adapterParams, 34)) - } - require(txType == 1 || txType == 2, "Unsupported txType"); - require(uaGas > 0, "Gas too low"); - - if (txType == 2) { - assembly { - airdropAmount := mload(add(_adapterParams, 66)) - airdropAddress := mload(add(_adapterParams, 86)) - } - } - } - - //--------------------------------------------------------------------------- - // Address type handling - function bytes32ToAddress(bytes32 _bytes32Address) internal pure returns (address _address) { - return address(uint160(uint256(_bytes32Address))); - } - - function addressToBytes32(address _address) internal pure returns (bytes32 _bytes32Address) { - return bytes32(uint256(uint160(_address))); - } -} From bb20bc47b35c0322aebd02df678e6fd88137b974 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 5 Sep 2024 12:58:19 +0530 Subject: [PATCH 3/6] added tests for l1 oft adapter --- test/OFT.t.sol | 89 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/test/OFT.t.sol b/test/OFT.t.sol index f191215..6c694ed 100644 --- a/test/OFT.t.sol +++ b/test/OFT.t.sol @@ -48,8 +48,6 @@ contract OFTTest is TestHelper { L2OFTAdapterMock cOFTAdapter; L2YnERC20 cERC20; - OFTInspectorMock oAppInspector; - address public userA = address(0x1); address public userB = address(0x2); address public userC = address(0x3); @@ -123,11 +121,6 @@ contract OFTTest is TestHelper { // mint tokens aERC20.mint(userA, initialBalance); - // bOFT.mint(userB, initialBalance); - // cERC20Mock.mint(userC, initialBalance); - - // deploy a universal inspector, can be used by each oft - oAppInspector = new OFTInspectorMock(); } function test_constructor() public view { @@ -370,6 +363,58 @@ contract OFTTest is TestHelper { aOFTAdapter.debit(amountToSendLD, minAmountToCreditLD, dstEid); } + function test_L1OFTAdapter_debit() public { + uint256 amountToSendLD = 1 ether; + uint256 minAmountToCreditLD = 1 ether; + uint32 dstEid = aEid; + + aERC20.mint(userC, initialBalance); + + assertEq(aERC20.balanceOf(userC), initialBalance, "incorrect user initial balance"); + assertEq(aERC20.balanceOf(address(this)), 0, "incorrect contract initial balance"); + assertEq(aERC20.balanceOf(address(aOFTAdapter)), 0, "incorrect adapter initial balance"); + + vm.expectRevert(abi.encodeWithSelector(IOFT.SlippageExceeded.selector, amountToSendLD, minAmountToCreditLD + 1)); + aOFTAdapter.debitView(amountToSendLD, minAmountToCreditLD + 1, dstEid); + + vm.startPrank(userC); + aERC20.approve(address(aOFTAdapter), amountToSendLD); + (uint256 amountDebitedLD, uint256 amountToCreditLD) = + aOFTAdapter.debit(amountToSendLD, minAmountToCreditLD, dstEid); + vm.stopPrank(); + + assertEq(amountDebitedLD, amountToSendLD); + assertEq(amountToCreditLD, amountToSendLD); + + assertEq(aERC20.balanceOf(userC), initialBalance - amountToSendLD, "incorrect user final balance"); + assertEq(aERC20.balanceOf(address(this)), 0, "incorrect contract final balance"); + // aOFT adapter should have 0 balance because it burns the incoming erc20 + assertEq(aERC20.balanceOf(address(aOFTAdapter)), amountToSendLD, "incorrect adapter final balance"); + } + + function test_L1OFTAdapter_credit() public { + uint256 amountToCreditLD = 1 ether; + uint32 srcEid = cEid; + + aERC20.mint(userB, initialBalance); + aERC20.mint(userC, initialBalance); + + assertEq(aERC20.balanceOf(userB), initialBalance, "incorrect userB initial balance"); + assertEq(aERC20.balanceOf(userC), initialBalance, "incorrect userC initial balance"); + assertEq(aERC20.balanceOf(address(this)), 0, "incorrect contract initial balance"); + assertEq(aERC20.balanceOf(address(aOFTAdapter)), 0, "incorrect adapter initial balance"); + + vm.prank(userC); + aERC20.transfer(address(aOFTAdapter), amountToCreditLD); + + uint256 amountReceived = aOFTAdapter.credit(userB, amountToCreditLD, srcEid); + + assertEq(aERC20.balanceOf(address(userB)), initialBalance + amountReceived, "incorrect userB final balance"); + assertEq(aERC20.balanceOf(address(userC)), initialBalance - amountReceived, "incorrect userC final balance"); + assertEq(aERC20.balanceOf(address(this)), 0, "incorrect contract final balance"); + assertEq(aERC20.balanceOf(address(aOFTAdapter)), 0, "incorrect adapter final balance"); + } + function test_L2OFTAdapter_debit() public { uint256 amountToSendLD = 1 ether; uint256 minAmountToCreditLD = 1 ether; @@ -379,45 +424,39 @@ contract OFTTest is TestHelper { cERC20.mint(userC, initialBalance); assertEq(cERC20.balanceOf(userC), initialBalance, "incorrect user initial balance"); + assertEq(cERC20.balanceOf(address(this)), 0, "incorrect contract initial balance"); assertEq(cERC20.balanceOf(address(cOFTAdapter)), 0, "incorrect adapter initial balance"); - vm.prank(userC); vm.expectRevert(abi.encodeWithSelector(IOFT.SlippageExceeded.selector, amountToSendLD, minAmountToCreditLD + 1)); cOFTAdapter.debitView(amountToSendLD, minAmountToCreditLD + 1, dstEid); - vm.prank(userC); + vm.startPrank(userC); cERC20.approve(address(cOFTAdapter), amountToSendLD); - vm.prank(userC); (uint256 amountDebitedLD, uint256 amountToCreditLD) = cOFTAdapter.debit(amountToSendLD, minAmountToCreditLD, dstEid); + vm.stopPrank(); assertEq(amountDebitedLD, amountToSendLD); assertEq(amountToCreditLD, amountToSendLD); - assertEq(cERC20.balanceOf(userC), initialBalance - amountToSendLD, "incorrect user ending balance"); + assertEq(cERC20.balanceOf(userC), initialBalance - amountToSendLD, "incorrect user final balance"); + assertEq(cERC20.balanceOf(address(this)), 0, "incorrect contract final balance"); // cOFT adapter should have 0 balance because it burns the incoming erc20 - assertEq(cERC20.balanceOf(address(cOFTAdapter)), 0, "incorrect adapter ending balance"); + assertEq(cERC20.balanceOf(address(cOFTAdapter)), 0, "incorrect adapter final balance"); } function test_L2OFTAdapter_credit() public { uint256 amountToCreditLD = 1 ether; uint32 srcEid = cEid; - cERC20.grantRole(cERC20.MINTER_ROLE(), address(this)); - cERC20.mint(userC, initialBalance); - - assertEq(cERC20.balanceOf(userC), initialBalance); - assertEq(cERC20.balanceOf(address(cOFTAdapter)), 0); - - vm.prank(userC); - cERC20.transfer(address(cOFTAdapter), amountToCreditLD); + assertEq(cERC20.balanceOf(userB), 0, "incorrect userB initial balance"); + assertEq(cERC20.balanceOf(address(this)), 0, "incorrect contract initial balance"); + assertEq(cERC20.balanceOf(address(cOFTAdapter)), 0, "incorrect adapter initial balance"); uint256 amountReceived = cOFTAdapter.credit(userB, amountToCreditLD, srcEid); - assertEq(cERC20.balanceOf(userC), initialBalance - amountToCreditLD, "incorrect userC ending balance"); - assertEq(cERC20.balanceOf(address(userB)), amountReceived, "incorrect userB ending balance"); - // note Should we burn incoming tokens on receive? - // assertEq(cERC20.balanceOf(address(cOFTAdapter)), 0, "incorrect adapter ending balance"); - assertEq(cERC20.balanceOf(address(cOFTAdapter)), amountReceived, "incorrect adapter ending balance"); + assertEq(cERC20.balanceOf(address(userB)), amountReceived, "incorrect userB final balance"); + assertEq(cERC20.balanceOf(address(this)), 0, "incorrect contract final balance"); + assertEq(cERC20.balanceOf(address(cOFTAdapter)), 0, "incorrect adapter final balance"); } } From 410c61a832410f0b181b4d43c7fee235091d209d Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 5 Sep 2024 13:12:28 +0530 Subject: [PATCH 4/6] renamed test --- test/CrossChainBaseTest.t.sol | 9 ++------- ...YnOFTAdapterUpgradeable.t.sol => OFTCrossChain.t.sol} | 6 +++++- 2 files changed, 7 insertions(+), 8 deletions(-) rename test/{L1YnOFTAdapterUpgradeable.t.sol => OFTCrossChain.t.sol} (96%) diff --git a/test/CrossChainBaseTest.t.sol b/test/CrossChainBaseTest.t.sol index 8bb2289..8a603f5 100644 --- a/test/CrossChainBaseTest.t.sol +++ b/test/CrossChainBaseTest.t.sol @@ -11,10 +11,9 @@ import {L2YnOFTAdapterUpgradeable} from "@adapters/L2YnOFTAdapterUpgradeable.sol import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol"; import {ERC20Mock} from "@layerzerolabs/lz-evm-oapp-v2/test/mocks/ERC20Mock.sol"; import {EndpointV2} from "@layerzerolabs/lz-evm-protocol-v2/contracts/EndpointV2.sol"; -import {TestHelper} from "@layerzerolabs/lz-evm-oapp-v2/test/TestHelper.sol"; import "forge-std/console.sol"; -contract CrossChainBaseTest is TestHelper { +contract CrossChainBaseTest is Test { ImmutableMultiChainDeployer public mainnetDeployer; ImmutableMultiChainDeployer public optimismDeployer; ImmutableMultiChainDeployer public arbitrumDeployer; @@ -49,7 +48,7 @@ contract CrossChainBaseTest is TestHelper { uint32 optimismEid; uint32 arbitrumEid; - function setUp() public virtual override { + function setUp() public virtual { // create forks optimismFork = vm.createFork(vm.envString("OPTIMISM_RPC_URL"), 124909408); arbitrumFork = vm.createFork(vm.envString("ARBITRUM_RPC_URL"), 249855816); @@ -148,10 +147,6 @@ contract CrossChainBaseTest is TestHelper { } vm.stopPrank(); - endpoints[mainnetEid] = address(mainnetLzEndpoint); - endpoints[optimismEid] = address(optimismLzEndpoint); - endpoints[arbitrumEid] = address(arbitrumLzEndpoint); - vm.startPrank(_owner); vm.selectFork(optimismFork); optimismERC20.grantRole(optimismERC20.MINTER_ROLE(), address(optimismOFTAdapter)); diff --git a/test/L1YnOFTAdapterUpgradeable.t.sol b/test/OFTCrossChain.t.sol similarity index 96% rename from test/L1YnOFTAdapterUpgradeable.t.sol rename to test/OFTCrossChain.t.sol index 16fd916..af2d68f 100644 --- a/test/L1YnOFTAdapterUpgradeable.t.sol +++ b/test/OFTCrossChain.t.sol @@ -18,7 +18,7 @@ import { IOFT, SendParam, OFTReceipt } from "@layerzerolabs/lz-evm-oapp-v2/contracts-upgradeable/oft/interfaces/IOFT.sol"; -contract Test_L1YnOFTAdapterUpgradeable is CrossChainBaseTest { +contract OFTCrossChainTest is CrossChainBaseTest { using OptionsBuilder for bytes; address public userA = address(0x1); @@ -132,4 +132,8 @@ contract Test_L1YnOFTAdapterUpgradeable is CrossChainBaseTest { // vm.selectFork(arbitrumFork); // assertEq(arbitrumERC20.balanceOf(userB), initialBalance + tokensToSend); } + + function addressToBytes32(address _addr) internal pure returns (bytes32) { + return bytes32(uint256(uint160(_addr))); + } } From 795ce49931aae5b42f8e4357b2d055e0ce078bc5 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 5 Sep 2024 13:50:03 +0530 Subject: [PATCH 5/6] refactored factory code --- remappings.txt | 2 +- src/factory/ImmutableMultiChainDeployer.sol | 139 ++++++++++-------- .../IImmutableMultiChainDeployer.sol | 103 ++++++++----- test/CrossChainBaseTest.t.sol | 6 +- test/MultiChainDeployer.t.sol | 8 +- test/OFT.t.sol | 2 +- test/OFTCrossChain.t.sol | 6 +- test/mocks/L1OFTAdapterMock.sol | 2 +- test/mocks/L2OFTAdapterMock.sol | 2 +- 9 files changed, 155 insertions(+), 115 deletions(-) diff --git a/remappings.txt b/remappings.txt index 6db31b8..cf1a001 100644 --- a/remappings.txt +++ b/remappings.txt @@ -9,7 +9,7 @@ forge-std/=node_modules/forge-std/src/ @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ @openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/ @solmate/=node_modules/solmate/src/ -@adapters/=src/ +@/=src/ @factory/=src/factory/ @interfaces/=src/interfaces/ solidity-bytes-utils/=node_modules/solidity-bytes-utils/ diff --git a/src/factory/ImmutableMultiChainDeployer.sol b/src/factory/ImmutableMultiChainDeployer.sol index 68fbe4b..43ed748 100644 --- a/src/factory/ImmutableMultiChainDeployer.sol +++ b/src/factory/ImmutableMultiChainDeployer.sol @@ -6,61 +6,57 @@ import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/acce import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol"; import {IImmutableMultiChainDeployer} from "@interfaces/IImmutableMultiChainDeployer.sol"; -import {L2YnOFTAdapterUpgradeable} from "@adapters/L2YnOFTAdapterUpgradeable.sol"; -import {L2YnERC20Upgradeable} from "@adapters/L2YnERC20Upgradeable.sol"; -import "forge-std/console.sol"; +import {L2YnOFTAdapterUpgradeable} from "@/L2YnOFTAdapterUpgradeable.sol"; +import {L2YnERC20Upgradeable} from "@/L2YnERC20Upgradeable.sol"; contract ImmutableMultiChainDeployer is IImmutableMultiChainDeployer { - event ContractCreated(address deployedAddress); + /// @notice Emitted when a new contract is deployed + /// @param _deployedAddress The address of the newly deployed contract + event ContractCreated(address indexed _deployedAddress); - // mapping to track the already deployed addresses - mapping(address => bool) private _deployed; + /// @notice Mapping to track deployed addresses + mapping(address => bool) private _deployedContracts; + + /// @dev Custom errors + error InvalidSalt(); + error AlreadyDeployed(); + error IncorrectDeploymentAddress(); /// @dev Modifier to ensure that the first 20 bytes of a submitted salt match - /// those of the calling account. This provides protection against the salt - /// being stolen by frontrunners or other attackers. The protection can also be - /// bypassed if desired by setting each of the first 20 bytes to zero. - /// @param salt bytes32 The salt value to check against the calling address. - modifier containsCaller(bytes32 salt) { - // prevent contract submissions from being stolen from tx.pool by requiring - // that the first 20 bytes of the submitted salt match msg.sender. - require( - (address(bytes20(salt)) == msg.sender) || (bytes20(salt) == bytes20(0)), - "Invalid salt - first 20 bytes of the salt must match calling address." - ); + /// those of the calling account, providing protection against salt misuse. + /// @param _salt The salt value to check against the calling address. + modifier containsCaller(bytes32 _salt) { + if (address(bytes20(_salt)) != msg.sender && bytes20(_salt) != bytes20(0)) { + revert InvalidSalt(); + } _; } - /// @inheritdoc IImmutableMultiChainDeployer - function deploy(bytes32 salt, bytes memory initCode) + /// @inheritdoc IImmutableMultiChainDeployer + function deploy(bytes32 _salt, bytes memory _initCode) public payable override - containsCaller(salt) - returns (address _deployedContract) + containsCaller(_salt) + returns (address deployedContract) { - // get target deployment - address targetDeploymentAddress = CREATE3.getDeployed(salt); - - require( - !_deployed[targetDeploymentAddress], - "Invalid deployment. a contract has already been deployed at this address" - ); + address _targetDeploymentAddress = CREATE3.getDeployed(_salt); - // use create 3 to deploy contract - _deployedContract = CREATE3.deploy(salt, initCode, msg.value); + if (_deployedContracts[_targetDeploymentAddress]) { + revert AlreadyDeployed(); + } - // check address against target to make sure deployment was successful - require(targetDeploymentAddress == _deployedContract, "failed to deploy to correct address"); + deployedContract = CREATE3.deploy(_salt, _initCode, msg.value); - // record the deployment of the contract to prevent redeploys. - _deployed[_deployedContract] = true; + if (_targetDeploymentAddress != deployedContract) { + revert IncorrectDeploymentAddress(); + } - // emit event - emit ContractCreated(_deployedContract); + _deployedContracts[deployedContract] = true; + emit ContractCreated(deployedContract); } - /// @inheritdoc IImmutableMultiChainDeployer + /// @inheritdoc IImmutableMultiChainDeployer function deployL2YnOFTAdapter( bytes32 _implSalt, bytes32 _proxySalt, @@ -70,45 +66,62 @@ contract ImmutableMultiChainDeployer is IImmutableMultiChainDeployer { RateLimiter.RateLimitConfig[] calldata _rateLimitConfigs, address _proxyController, bytes memory _l2YnOFTAdapterBytecode - ) public returns (address _deployedContract) { - bytes memory constructorParams = abi.encode(_token, _lzEndpoint); - bytes memory contractCode = abi.encodePacked(_l2YnOFTAdapterBytecode, constructorParams); - - address adapterImpl = deploy(_implSalt, contractCode); - _deployedContract = deployProxy(_proxySalt, adapterImpl, _proxyController); - L2YnOFTAdapterUpgradeable(_deployedContract).initialize(_owner, _rateLimitConfigs); + ) public override returns (address deployedContract) { + bytes memory _constructorParams = abi.encode(_token, _lzEndpoint); + bytes memory _contractCode = abi.encodePacked(_l2YnOFTAdapterBytecode, _constructorParams); + bytes memory _initializeArgs = + abi.encodeWithSelector(L2YnOFTAdapterUpgradeable.initialize.selector, _owner, _rateLimitConfigs); + deployedContract = + deployContractAndProxy(_implSalt, _proxySalt, _proxyController, _contractCode, _initializeArgs); } - /// @inheritdoc IImmutableMultiChainDeployer + /// @inheritdoc IImmutableMultiChainDeployer function deployL2YnERC20( bytes32 _implSalt, bytes32 _proxySalt, - string memory _name, - string memory _symbol, + string calldata _name, + string calldata _symbol, address _owner, address _proxyController, bytes memory _l2YnERC20UpgradeableByteCode - ) public returns (address _deployedContract) { - address adapterImpl = deploy(_implSalt, _l2YnERC20UpgradeableByteCode); - _deployedContract = deployProxy(_proxySalt, adapterImpl, _proxyController); - L2YnERC20Upgradeable(_deployedContract).initialize(_name, _symbol, _owner); + ) public override returns (address deployedContract) { + bytes memory _initializeArgs = + abi.encodeWithSelector(L2YnERC20Upgradeable.initialize.selector, _name, _symbol, _owner); + deployedContract = deployContractAndProxy( + _implSalt, _proxySalt, _proxyController, _l2YnERC20UpgradeableByteCode, _initializeArgs + ); } - /// @inheritdoc IImmutableMultiChainDeployer - function getDeployed(bytes32 salt) public view override returns (address deployed) { - // hash salt with the deployer address to give each deployer its own namespace - return CREATE3.getDeployed(salt); + /// @inheritdoc IImmutableMultiChainDeployer + function getDeployed(bytes32 _salt) external view override returns (address deployed) { + return CREATE3.getDeployed(_salt); } - function hasBeenDeployed(address deploymentAddress) external view returns (bool) { - // determine if a contract has been deployed to the provided address. - return _deployed[deploymentAddress]; + /// @inheritdoc IImmutableMultiChainDeployer + function hasBeenDeployed(address _deploymentAddress) external view override returns (bool beenDeployed) { + beenDeployed = _deployedContracts[_deploymentAddress]; } - function deployProxy(bytes32 salt, address implementation, address controller) internal returns (address proxy) { - bytes memory bytecode = type(TransparentUpgradeableProxy).creationCode; - bytes memory constructorParams = abi.encode(implementation, controller, ""); - bytes memory contractCode = abi.encodePacked(bytecode, constructorParams); - proxy = deploy(salt, contractCode); + /// @inheritdoc IImmutableMultiChainDeployer + function deployProxy(bytes32 _salt, address _implementation, address _controller, bytes memory _initializeArgs) + public + returns (address proxy) + { + bytes memory _constructorParams = abi.encode(_implementation, _controller, _initializeArgs); + bytes memory _contractCode = + abi.encodePacked(type(TransparentUpgradeableProxy).creationCode, _constructorParams); + proxy = deploy(_salt, _contractCode); + } + + /// @inheritdoc IImmutableMultiChainDeployer + function deployContractAndProxy( + bytes32 _implSalt, + bytes32 _proxySalt, + address _controller, + bytes memory _bytecode, + bytes memory _initializeArgs + ) public returns (address addr) { + address _implAddr = deploy(_implSalt, _bytecode); + return deployProxy(_proxySalt, _implAddr, _controller, _initializeArgs); } } diff --git a/src/interfaces/IImmutableMultiChainDeployer.sol b/src/interfaces/IImmutableMultiChainDeployer.sol index 32dfe74..f11502f 100644 --- a/src/interfaces/IImmutableMultiChainDeployer.sol +++ b/src/interfaces/IImmutableMultiChainDeployer.sol @@ -1,29 +1,31 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity >=0.6.0; +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol"; /// @title Factory for deploying yieldnest contracts to deterministic addresses via CREATE3 -/// @author Raid Guild /// @notice Enables deploying contracts using CREATE3 and then initializing the upgradeable contracts. Each deployer (msg.sender) has /// its own namespace for deployed addresses. +/// @dev Uses CREATE3 for deterministic contract deployment. interface IImmutableMultiChainDeployer { /// @notice Deploys a contract using CREATE3 - /// @dev The provided salt is hashed together with msg.sender to generate the final salt - /// @param salt The deployer-specific salt for determining the deployed contract's address - /// @param creationCode The creation code of the contract to deploy - /// @return deployed The address of the deployed contract + /// @dev The provided salt is combined with msg.sender to create a unique deployment address. + /// @param salt A deployer-specific salt for determining the deployed contract's address. + /// @param creationCode The creation code of the contract to deploy. + /// @return deployed The address of the deployed contract. function deploy(bytes32 salt, bytes calldata creationCode) external payable returns (address deployed); - /// @notice Deploys a deployOFTAdapter contract using CREATE3 and initializes in the same call - /// @dev The provided salt is hashed together with msg.sender to generate the final salt - /// @param _implSalt the salt for the oft adapter to be passed to the initializer - /// @param _proxySalt the salt for the oft adapter to be passed to the initializer - /// @param _token the token address for the oft adapter to be passed to the initializer - /// @param _lzEndpoint the lz endpoint for the oft adapter to be passed to the initializer - /// @param _rateLimitConfigs the desired rate limit configs for the oft adapter to be passed to the initializer - /// @param _proxyController the proxy controller of the erc20 to be passed to the initializer - /// @return deployed The address of the deployed contract + /// @notice Deploys and initializes a deployOFTAdapter contract using CREATE3. + /// @dev The provided salts and parameters are used to configure the deployment and initialization. + /// @param _implSalt The salt for the OFT adapter implementation. + /// @param _proxySalt The salt for the OFT adapter proxy. + /// @param _token The token address for the OFT adapter. + /// @param _lzEndpoint The LayerZero endpoint for the OFT adapter. + /// @param _owner The owner address for the OFT adapter. + /// @param _rateLimitConfigs The rate limit configurations for the OFT adapter. + /// @param _proxyController The proxy controller address for the OFT adapter. + /// @param _l2YnOFTAdapterBytecode The bytecode of the L2YnOFTAdapter contract to deploy. + /// @return deployed The address of the deployed contract. function deployL2YnOFTAdapter( bytes32 _implSalt, bytes32 _proxySalt, @@ -32,37 +34,62 @@ interface IImmutableMultiChainDeployer { address _owner, RateLimiter.RateLimitConfig[] calldata _rateLimitConfigs, address _proxyController, - bytes memory _l2YnOFTAdapterBytecode + bytes calldata _l2YnOFTAdapterBytecode ) external returns (address deployed); - /// @notice Deploys a deployYnERC20 contract using CREATE3 and initializes in the same call - /// @dev The provided salt is hashed together with msg.sender to generate the final salt - /// @param _implSalt the salt for the oft adapter to be passed to the initializer - /// @param _proxySalt the salt for the oft adapter to be passed to the initializer - /// @param _name the name of the erc20 to be passed to the initializer - /// @param _symbol the symbol of the erc20 to be passed to the initializer - /// @param _owner the owner of the erc20 to be passed to the initializer - /// @param _proxyController the proxy controller of the erc20 to be passed to the initializer - /// @return deployed The address of the deployed contract + /// @notice Deploys and initializes a deployYnERC20 contract using CREATE3. + /// @dev The provided salts and parameters are used to configure the deployment and initialization. + /// @param _implSalt The salt for the ERC20 implementation. + /// @param _proxySalt The salt for the ERC20 proxy. + /// @param _name The name of the ERC20 token. + /// @param _symbol The symbol of the ERC20 token. + /// @param _owner The owner address of the ERC20 token. + /// @param _proxyController The proxy controller address of the ERC20 token. + /// @param _l2YnOFTAdapterBytecode The bytecode of the L2YnOFTAdapter contract to deploy. + /// @return deployed The address of the deployed contract. function deployL2YnERC20( bytes32 _implSalt, bytes32 _proxySalt, - string memory _name, - string memory _symbol, + string calldata _name, + string calldata _symbol, address _owner, address _proxyController, - bytes memory _l2YnOFTAdapterBytecode + bytes calldata _l2YnOFTAdapterBytecode ) external returns (address deployed); - /// @notice Predicts the address of a deployed contract - /// @dev The provided salt is hashed together with the deployer address to generate the final salt - /// @param salt The deployer-specific salt for determining the deployed contract's address - /// @return deployed The address of the contract that will be deployed + /// @notice Predicts the address of a contract deployed using CREATE3. + /// @dev The provided salt is combined with the deployer address to create a unique predicted address. + /// @param salt A deployer-specific salt for determining the deployed contract's address. + /// @return deployed The address of the contract that will be deployed. function getDeployed(bytes32 salt) external view returns (address deployed); - /// @dev Determine if a contract has already been deployed by the factory to a - /// given address. - /// @param deploymentAddress address The contract address to check. - /// @return True if the contract has been deployed, false otherwise. - function hasBeenDeployed(address deploymentAddress) external view returns (bool); + /// @notice Checks if a contract has already been deployed by the factory to a specific address. + /// @param deploymentAddress The contract address to check. + /// @return beenDeployed as true if the contract has been deployed, false otherwise. + function hasBeenDeployed(address deploymentAddress) external view returns (bool beenDeployed); + + /// @notice Deploys a TransparentUpgradeableProxy with given parameters. + /// @param salt The salt used for deployment. + /// @param implementation The address of the implementation contract. + /// @param controller The address of the proxy controller. + /// @param _initializeArgs The initialization arguments for the proxy. + /// @return proxy The address of the deployed proxy. + function deployProxy(bytes32 salt, address implementation, address controller, bytes memory _initializeArgs) + external + returns (address proxy); + + /// @notice Deploys an implementation and proxy contract. + /// @param _implSalt The salt used for the implementation deployment. + /// @param _proxySalt The salt used for the proxy deployment. + /// @param _controller The address of the proxy controller. + /// @param _bytecode The bytecode of the implementation contract. + /// @param _initializeArgs The initialization arguments for the proxy. + /// @return addr The address of the deployed proxy. + function deployContractAndProxy( + bytes32 _implSalt, + bytes32 _proxySalt, + address _controller, + bytes memory _bytecode, + bytes memory _initializeArgs + ) external returns (address addr); } diff --git a/test/CrossChainBaseTest.t.sol b/test/CrossChainBaseTest.t.sol index 8a603f5..5a4414e 100644 --- a/test/CrossChainBaseTest.t.sol +++ b/test/CrossChainBaseTest.t.sol @@ -5,9 +5,9 @@ import {Test} from "forge-std/Test.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {ImmutableMultiChainDeployer} from "@factory/ImmutableMultiChainDeployer.sol"; import {IMintableBurnableERC20} from "@interfaces/IMintableBurnableERC20.sol"; -import {L1YnOFTAdapterUpgradeable} from "@adapters/L1YnOFTAdapterUpgradeable.sol"; -import {L2YnERC20Upgradeable} from "@adapters/L2YnERC20Upgradeable.sol"; -import {L2YnOFTAdapterUpgradeable} from "@adapters/L2YnOFTAdapterUpgradeable.sol"; +import {L1YnOFTAdapterUpgradeable} from "@/L1YnOFTAdapterUpgradeable.sol"; +import {L2YnERC20Upgradeable} from "@/L2YnERC20Upgradeable.sol"; +import {L2YnOFTAdapterUpgradeable} from "@/L2YnOFTAdapterUpgradeable.sol"; import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol"; import {ERC20Mock} from "@layerzerolabs/lz-evm-oapp-v2/test/mocks/ERC20Mock.sol"; import {EndpointV2} from "@layerzerolabs/lz-evm-protocol-v2/contracts/EndpointV2.sol"; diff --git a/test/MultiChainDeployer.t.sol b/test/MultiChainDeployer.t.sol index c9aaec7..dcb0354 100644 --- a/test/MultiChainDeployer.t.sol +++ b/test/MultiChainDeployer.t.sol @@ -4,9 +4,9 @@ pragma solidity ^0.8.24; import {CrossChainBaseTest} from "./CrossChainBaseTest.t.sol"; import {ImmutableMultiChainDeployer} from "@factory/ImmutableMultiChainDeployer.sol"; import {IMintableBurnableERC20} from "@interfaces/IMintableBurnableERC20.sol"; -import {L1YnOFTAdapterUpgradeable} from "@adapters/L1YnOFTAdapterUpgradeable.sol"; -import {L2YnERC20Upgradeable} from "@adapters/L2YnERC20Upgradeable.sol"; -import {L2YnOFTAdapterUpgradeable} from "@adapters/L2YnOFTAdapterUpgradeable.sol"; +import {L1YnOFTAdapterUpgradeable} from "@/L1YnOFTAdapterUpgradeable.sol"; +import {L2YnERC20Upgradeable} from "@/L2YnERC20Upgradeable.sol"; +import {L2YnOFTAdapterUpgradeable} from "@/L2YnOFTAdapterUpgradeable.sol"; import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol"; contract Test_ImmutableMultiChainDeployer is CrossChainBaseTest { @@ -26,7 +26,7 @@ contract Test_ImmutableMultiChainDeployer is CrossChainBaseTest { RateLimiter.RateLimitConfig[] memory _rateLimitConfigs = new RateLimiter.RateLimitConfig[](1); _rateLimitConfigs[0] = RateLimiter.RateLimitConfig({dstEid: uint32(1), limit: 1 ether, window: 1 days}); - vm.expectRevert("Invalid salt - first 20 bytes of the salt must match calling address."); + vm.expectRevert(ImmutableMultiChainDeployer.InvalidSalt.selector); address( arbitrumDeployer.deployL2YnOFTAdapter( keccak256(abi.encode("test")), diff --git a/test/OFT.t.sol b/test/OFT.t.sol index 6c694ed..e10d98d 100644 --- a/test/OFT.t.sol +++ b/test/OFT.t.sol @@ -30,7 +30,7 @@ import {TestHelper, Initializable} from "@layerzerolabs/lz-evm-oapp-v2/test/Test import {L1OFTAdapterMock} from "./mocks/L1OFTAdapterMock.sol"; import {L2OFTAdapterMock} from "./mocks/L2OFTAdapterMock.sol"; -import {L2YnERC20Upgradeable as L2YnERC20} from "@adapters/L2YnERC20Upgradeable.sol"; +import {L2YnERC20Upgradeable as L2YnERC20} from "@/L2YnERC20Upgradeable.sol"; import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol"; diff --git a/test/OFTCrossChain.t.sol b/test/OFTCrossChain.t.sol index af2d68f..ae47fd5 100644 --- a/test/OFTCrossChain.t.sol +++ b/test/OFTCrossChain.t.sol @@ -4,9 +4,9 @@ pragma solidity ^0.8.24; import {CrossChainBaseTest} from "./CrossChainBaseTest.t.sol"; import {ImmutableMultiChainDeployer} from "@factory/ImmutableMultiChainDeployer.sol"; import {IMintableBurnableERC20} from "@interfaces/IMintableBurnableERC20.sol"; -import {L1YnOFTAdapterUpgradeable} from "@adapters/L1YnOFTAdapterUpgradeable.sol"; -import {L2YnERC20Upgradeable} from "@adapters/L2YnERC20Upgradeable.sol"; -import {L2YnOFTAdapterUpgradeable} from "@adapters/L2YnOFTAdapterUpgradeable.sol"; +import {L1YnOFTAdapterUpgradeable} from "@/L1YnOFTAdapterUpgradeable.sol"; +import {L2YnERC20Upgradeable} from "@/L2YnERC20Upgradeable.sol"; +import {L2YnOFTAdapterUpgradeable} from "@/L2YnOFTAdapterUpgradeable.sol"; import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol"; import {OptionsBuilder} from "@layerzerolabs/lz-evm-oapp-v2/contracts-upgradeable/oapp/libs/OptionsBuilder.sol"; import { diff --git a/test/mocks/L1OFTAdapterMock.sol b/test/mocks/L1OFTAdapterMock.sol index fe0fe36..26a726e 100644 --- a/test/mocks/L1OFTAdapterMock.sol +++ b/test/mocks/L1OFTAdapterMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; -import {L1YnOFTAdapterUpgradeable} from "../../src/L1YnOFTAdapterUpgradeable.sol"; +import {L1YnOFTAdapterUpgradeable} from "@/L1YnOFTAdapterUpgradeable.sol"; import {OFTAdapterUpgradeable} from "@layerzerolabs/lz-evm-oapp-v2/contracts-upgradeable/oft/OFTAdapterUpgradeable.sol"; import {OFTUpgradeable} from "@layerzerolabs/lz-evm-oapp-v2/contracts-upgradeable/oft/OFTUpgradeable.sol"; diff --git a/test/mocks/L2OFTAdapterMock.sol b/test/mocks/L2OFTAdapterMock.sol index b14fe21..d99cf65 100644 --- a/test/mocks/L2OFTAdapterMock.sol +++ b/test/mocks/L2OFTAdapterMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; -import {L2YnOFTAdapterUpgradeable} from "../../src/L2YnOFTAdapterUpgradeable.sol"; +import {L2YnOFTAdapterUpgradeable} from "@/L2YnOFTAdapterUpgradeable.sol"; import {OFTAdapterUpgradeable} from "@layerzerolabs/lz-evm-oapp-v2/contracts-upgradeable/oft/OFTAdapterUpgradeable.sol"; import {OFTUpgradeable} from "@layerzerolabs/lz-evm-oapp-v2/contracts-upgradeable/oft/OFTUpgradeable.sol"; From a32f2406fcdb29bf84967f871154c340c3691fa6 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Thu, 5 Sep 2024 19:25:45 +0530 Subject: [PATCH 6/6] added base script --- foundry.toml | 47 ++++++++++++++++------- script/BaseData.sol | 85 +++++++++++++++++++++++++++++++++++++++++ script/BaseScript.s.sol | 20 ++++++++++ 3 files changed, 138 insertions(+), 14 deletions(-) create mode 100644 script/BaseData.sol create mode 100644 script/BaseScript.s.sol diff --git a/foundry.toml b/foundry.toml index 5e2b20f..7b43e9a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,15 +1,34 @@ [profile.default] -src = "src" -out = "out" -libs = ["lib"] -test = 'test' -cache_path = 'cache' -fs_permissions = [ - { access = "read-write", path = "./deployments" }, - { access = "read", path = "./" }, -] -optimizer = true -optimizer-runs = 200 -evm_version = "cancun" -solc_version = "0.8.24" -prompt_timeout = 120 + src = "src" + out = "out" + libs = ["lib"] + test = 'test' + cache_path = 'cache' + fs_permissions = [ + { access = "read-write", path = "./deployments" }, + { access = "read", path = "./" }, + ] + optimizer = true + optimizer-runs = 200 + evm_version = "cancun" + solc_version = "0.8.24" + prompt_timeout = 120 + +[rpc_endpoints] + mainnet = "${MAINNET_RPC_URL}" + arbitrum = "${ARBITRUM_RPC_URL}" + optimism = "${OPTIMISM_RPC_URL}" + base = "${BASE_RPC_URL}" + fraxtal = "${FRAXTAL_RPC_URL}" + holesky = "${HOLESKY_RPC_URL}" + fraxtal_testnet = "${FRAXTAL_TESTNET_RPC_URL}" + +[etherscan] + mainnet = { key = "${ETHERSCAN_API_KEY}" } + arbitrum = { key = "${ARBISCAN_API_KEY}" } + optimism = { key = "${OPTIMISTIC_ETHERSCAN_API_KEY}" } + base = { key = "${BASESCAN_API_KEY}", url = "https://api.basescan.org/api/" } + holesky = { key = "${ETHERSCAN_API_KEY}" } + fraxtal = { key = "${FRAXSCAN_API_KEY}", url = "https://api.fraxscan.io/api/" } + fraxtal_testnet = { key = "${FRAXSCAN_API_KEY}", url = "https://api-holesky.fraxscan.io/api/" } + diff --git a/script/BaseData.sol b/script/BaseData.sol new file mode 100644 index 0000000..ed1e377 --- /dev/null +++ b/script/BaseData.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIt +pragma solidity ^0.8.24; + +import {Script} from "forge-std/Script.sol"; + +contract BaseData is Script { + struct Actors { + address OFT_DELEGATE; + address TOKEN_ADMIN; + address PROXY_ADMIN; + } + + struct ChainAddresses { + address lzEndpoint; + } + + struct ChainIds { + uint256 mainnet; + uint256 base; + uint256 optimism; + uint256 arbitrum; + uint256 fraxtal; + uint256 holeksy; + uint256 fraxtalTestnet; + } + + mapping(uint256 => Actors) public actors; + mapping(uint256 => ChainAddresses) public addresses; + + ChainIds public chainIds = ChainIds({ + mainnet: 1, + base: 8453, + optimism: 10, + arbitrum: 42161, + fraxtal: 252, + holeksy: 17000, + fraxtalTestnet: 2522 + }); + + function setUp() public virtual { + addresses[chainIds.mainnet] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c}); + actors[chainIds.mainnet] = Actors({ + OFT_DELEGATE: 0xfcad670592a3b24869C0b51a6c6FDED4F95D6975, // yn security council + TOKEN_ADMIN: 0xfcad670592a3b24869C0b51a6c6FDED4F95D6975, + PROXY_ADMIN: 0xfcad670592a3b24869C0b51a6c6FDED4F95D6975 + }); + + addresses[chainIds.fraxtal] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c}); + actors[chainIds.fraxtal] = Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)}); + + addresses[chainIds.optimism] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c}); + actors[chainIds.optimism] = Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)}); + + addresses[chainIds.arbitrum] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c}); + actors[chainIds.arbitrum] = Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)}); + + addresses[chainIds.base] = ChainAddresses({lzEndpoint: 0x1a44076050125825900e736c501f859c50fE728c}); + actors[chainIds.base] = Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)}); + + addresses[chainIds.holeksy] = ChainAddresses({lzEndpoint: 0x6EDCE65403992e310A62460808c4b910D972f10f}); + actors[chainIds.holeksy] = Actors({ + OFT_DELEGATE: 0x743b91CDB1C694D4F51bCDA3a4A59DcC0d02b913, // yn security council + TOKEN_ADMIN: 0x743b91CDB1C694D4F51bCDA3a4A59DcC0d02b913, + PROXY_ADMIN: 0x743b91CDB1C694D4F51bCDA3a4A59DcC0d02b913 + }); + + addresses[chainIds.fraxtalTestnet] = ChainAddresses({lzEndpoint: 0x6EDCE65403992e310A62460808c4b910D972f10f}); + actors[chainIds.fraxtalTestnet] = + Actors({OFT_DELEGATE: address(0), TOKEN_ADMIN: address(0), PROXY_ADMIN: address(0)}); + } + + function getActors(uint256 chainId) external view returns (Actors memory) { + return actors[chainId]; + } + + function getChainAddresses(uint256 chainId) external view returns (ChainAddresses memory) { + return addresses[chainId]; + } + + function isSupportedChainId(uint256 chainId) external view returns (bool) { + return chainId == chainIds.mainnet || chainId == chainIds.base || chainId == chainIds.fraxtal + || chainId == chainIds.optimism || chainId == chainIds.arbitrum || chainId == chainIds.holeksy + || chainId == chainIds.fraxtalTestnet; + } +} diff --git a/script/BaseScript.s.sol b/script/BaseScript.s.sol new file mode 100644 index 0000000..66336cf --- /dev/null +++ b/script/BaseScript.s.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {stdJson} from "forge-std/StdJson.sol"; +import {console} from "forge-std/console.sol"; + +import {BaseData} from "script/BaseData.sol"; + +abstract contract BaseScript is BaseData { + using stdJson for string; + + function setUp() public virtual override { + super.setUp(); + console.log("BaseScript.setUp"); + + // TODO: parse token address from json or as input from user + // TODO: setup forks based on if testnet or mainnet deployment as per json + // TODO: setup saving of deployment data in deployments json file + } +}