From c94d0adaf315df150af988aee7e5149287d70341 Mon Sep 17 00:00:00 2001 From: dan13ram Date: Tue, 3 Sep 2024 21:08:34 +0530 Subject: [PATCH] deployment working --- package.json | 2 +- remappings.txt | 1 + src/L2YnERC20Upgradeable.sol | 5 +- src/factory/MultiChainDeployer.sol | 69 +++++++-------- src/interfaces/IMultiChainDeployer.sol | 48 +++++------ test/CrossChainBaseTest.sol | 111 ++++++++++++++++++------- test/MultiChainDeployer.t.sol | 10 ++- 7 files changed, 147 insertions(+), 99 deletions(-) diff --git a/package.json b/package.json index 2db5325..6822f76 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "build": "yarn install && forge build", "compile": "forge compile", "format": "forge fmt --root .", - "test": "forge test", + "test": "forge test -vvv", "prepare": "husky" } } diff --git a/remappings.txt b/remappings.txt index 10bcb70..5fa2a29 100644 --- a/remappings.txt +++ b/remappings.txt @@ -4,6 +4,7 @@ forge-std/=node_modules/forge-std/src/ @layerzerolabs/lz-evm-protocol-v2/contracts/=node_modules/@layerzerolabs/lz-evm-protocol-v2/contracts/ @layerzerolabs/lz-evm-messagelib-v2/contracts/=node_modules/@layerzerolabs/lz-evm-messagelib-v2/contracts/ @layerzerolabs/lz-evm-oapp-v2/contracts-upgradeable/=node_modules/layerzero-v2/oapp/contracts/ +@layerzerolabs/lz-evm-oapp-v2/test/=node_modules/layerzero-v2/oapp/test/ @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ @openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/ @solmate/=lib/solmate/src/ diff --git a/src/L2YnERC20Upgradeable.sol b/src/L2YnERC20Upgradeable.sol index bf39e2c..0950c6e 100644 --- a/src/L2YnERC20Upgradeable.sol +++ b/src/L2YnERC20Upgradeable.sol @@ -13,12 +13,11 @@ contract L2YnERC20Upgradeable is ERC20Upgradeable, AccessControlUpgradeable, IMi _disableInitializers(); } - function initialize(string memory _name, string memory _symbol, address _minter) public initializer { + function initialize(string memory _name, string memory _symbol, address _owner) public initializer { __ERC20_init(_name, _symbol); __AccessControl_init(); - _grantRole(DEFAULT_ADMIN_ROLE, _msgSender()); - _grantRole(MINTER_ROLE, _minter); + _grantRole(DEFAULT_ADMIN_ROLE, _owner); } function mint(address _to, uint256 _amount) public onlyRole(MINTER_ROLE) { diff --git a/src/factory/MultiChainDeployer.sol b/src/factory/MultiChainDeployer.sol index 8f5da7e..28a8ae7 100644 --- a/src/factory/MultiChainDeployer.sol +++ b/src/factory/MultiChainDeployer.sol @@ -3,11 +3,11 @@ pragma solidity ^0.8.24; 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"; import {IMultiChainDeployer} from "@interfaces/IMultiChainDeployer.sol"; import {L2YnOFTAdapterUpgradeable} from "@adapters/L2YnOFTAdapterUpgradeable.sol"; import {L2YnERC20Upgradeable} from "@adapters/L2YnERC20Upgradeable.sol"; -import "forge-std/console.sol"; contract MultiChainDeployer is IMultiChainDeployer { event ContractCreated(address deployedAddress); @@ -23,8 +23,6 @@ contract MultiChainDeployer is IMultiChainDeployer { 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. - console.log(address(bytes20(salt))); - console.log(msg.sender); require( (address(bytes20(salt)) == msg.sender) || (bytes20(salt) == bytes20(0)), "Invalid salt - first 20 bytes of the salt must match calling address." @@ -33,18 +31,15 @@ contract MultiChainDeployer is IMultiChainDeployer { } /// @inheritdoc IMultiChainDeployer - function deploy(bytes32 salt, bytes calldata creationCode) + function deploy(bytes32 salt, bytes memory initCode) public payable override containsCaller(salt) returns (address _deployedContract) { - // move the initialization code from calldata to memory. - bytes memory initCode = creationCode; - // get target deployment - address targetDeploymentAddress = getDeployed(msg.sender, salt); + address targetDeploymentAddress = CREATE3.getDeployed(salt); require( !_deployed[targetDeploymentAddress], @@ -65,32 +60,39 @@ contract MultiChainDeployer is IMultiChainDeployer { } /// @inheritdoc IMultiChainDeployer - function deployOFTAdapter( - bytes32 salt, - bytes calldata creationCode, + function deployL2YnOFTAdapter( + bytes32 _implSalt, + bytes32 _proxySalt, + address _token, + address _lzEndpoint, + address _owner, RateLimiter.RateLimitConfig[] calldata _rateLimitConfigs ) public returns (address _deployedContract) { - //deploy the contract with create3 - _deployedContract = this.deploy(salt, creationCode); - // initialize the YnOFTAdapter - initializeOFTAdapter(_deployedContract, _rateLimitConfigs); + bytes memory bytecode = type(L2YnOFTAdapterUpgradeable).creationCode; + bytes memory constructorParams = abi.encode(_token, _lzEndpoint); + bytes memory contractCode = abi.encodePacked(bytecode, constructorParams); + + address adapterImpl = deploy(_implSalt, contractCode); + _deployedContract = deployProxy(_proxySalt, adapterImpl, _owner); + L2YnOFTAdapterUpgradeable(_deployedContract).initialize(_owner, _rateLimitConfigs); } /// @inheritdoc IMultiChainDeployer - function deployYnERC20(bytes32 salt, bytes calldata creationCode, string memory _name, string memory _symbol) - public - returns (address _deployedContract) - { - //deploy the contract with create3 - _deployedContract = _deployedContract = this.deploy(salt, creationCode); - // initialize the deployed ERC20 - initializeYnERC20Upgradeable(_deployedContract, _name, _symbol); + function deployL2YnERC20( + bytes32 _implSalt, + bytes32 _proxySalt, + string memory _name, + string memory _symbol, + address _owner + ) public returns (address _deployedContract) { + address adapterImpl = deploy(_implSalt, type(L2YnERC20Upgradeable).creationCode); + _deployedContract = deployProxy(_proxySalt, adapterImpl, _owner); + L2YnERC20Upgradeable(_deployedContract).initialize(_name, _symbol, _owner); } /// @inheritdoc IMultiChainDeployer - function getDeployed(address deployer, bytes32 salt) public view override returns (address deployed) { + function getDeployed(bytes32 salt) public view override returns (address deployed) { // hash salt with the deployer address to give each deployer its own namespace - salt = keccak256(abi.encodePacked(deployer, salt)); return CREATE3.getDeployed(salt); } @@ -99,17 +101,10 @@ contract MultiChainDeployer is IMultiChainDeployer { return _deployed[deploymentAddress]; } - /// @inheritdoc IMultiChainDeployer - function initializeOFTAdapter(address _deployedContract, RateLimiter.RateLimitConfig[] calldata _rateLimitConfigs) - public - { - L2YnOFTAdapterUpgradeable(_deployedContract).initialize(msg.sender, _rateLimitConfigs); - } - - /// @inheritdoc IMultiChainDeployer - function initializeYnERC20Upgradeable(address _deployedContract, string memory _name, string memory _symbol) - public - { - L2YnERC20Upgradeable(_deployedContract).initialize(_name, _symbol, msg.sender); + 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); } } diff --git a/src/interfaces/IMultiChainDeployer.sol b/src/interfaces/IMultiChainDeployer.sol index 7509d0a..4f6a18d 100644 --- a/src/interfaces/IMultiChainDeployer.sol +++ b/src/interfaces/IMultiChainDeployer.sol @@ -17,52 +17,46 @@ interface IMultiChainDeployer { /// @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 salt The deployer-specific salt for determining the deployed contract's address - /// @param creationCode The creation code of the contract to deploy + /// @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 /// @return deployed The address of the deployed contract - function deployOFTAdapter( - bytes32 salt, - bytes calldata creationCode, + function deployL2YnOFTAdapter( + bytes32 _implSalt, + bytes32 _proxySalt, + address _token, + address _lzEndpoint, + address _owner, RateLimiter.RateLimitConfig[] calldata _rateLimitConfigs ) 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 salt The deployer-specific salt for determining the deployed contract's address - /// @param creationCode The creation code of the contract to deploy + /// @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 /// @return deployed The address of the deployed contract - function deployYnERC20(bytes32 salt, bytes calldata creationCode, string memory _name, string memory _symbol) - external - returns (address deployed); + function deployL2YnERC20( + bytes32 _implSalt, + bytes32 _proxySalt, + string memory _name, + string memory _symbol, + address _owner + ) 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 deployer The deployer account that will call deploy() /// @param salt The deployer-specific salt for determining the deployed contract's address /// @return deployed The address of the contract that will be deployed - function getDeployed(address deployer, bytes32 salt) external view returns (address 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 Initializes a deployed YnOFTAdapter - /// @dev This is intended to be called atomically in the deployOFTAdapter, but can be called seperatly as well - /// @param _deployedContract the address of the deployed contract - /// @param _rateLimitConfigs the desired rate limit configs for the oft adapter - function initializeOFTAdapter(address _deployedContract, RateLimiter.RateLimitConfig[] calldata _rateLimitConfigs) - external; - - /// @notice Initializes a deployed YnERC20Upgradeable contract - /// @dev This is intended to be called atomically in the deployYnERC20 call, but can be called seperatly as well - /// @param _deployedContract the address of the deployed contract - /// @param _name the name of the erc20 - /// @param _symbol the symbol of the erc20 - function initializeYnERC20Upgradeable(address _deployedContract, string memory _name, string memory _symbol) - external; } diff --git a/test/CrossChainBaseTest.sol b/test/CrossChainBaseTest.sol index 0c98c26..33d842e 100644 --- a/test/CrossChainBaseTest.sol +++ b/test/CrossChainBaseTest.sol @@ -8,24 +8,35 @@ import {L1YnOFTAdapterUpgradeable} from "@adapters/L1YnOFTAdapterUpgradeable.sol import {L2YnERC20Upgradeable} from "@adapters/L2YnERC20Upgradeable.sol"; 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 "forge-std/console.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; contract CrossChainBaseTest is Test { MultiChainDeployer public mainnetDeployer; MultiChainDeployer public optimismDeployer; - MultiChainDeployer public baseDeployer; MultiChainDeployer public arbitrumDeployer; - MultiChainDeployer public fraxDeployer; + // MultiChainDeployer public baseDeployer; + // MultiChainDeployer public fraxDeployer; - L1YnOFTAdapterUpgradeable public l1OFTAdapter; - L2YnERC20Upgradeable public l2YnERC20; - L2YnOFTAdapterUpgradeable public l2OFTAdapter; + L1YnOFTAdapterUpgradeable public mainnetOFTAdapter; + L2YnOFTAdapterUpgradeable public optimismOFTAdapter; + L2YnOFTAdapterUpgradeable public arbitrumOFTAdapter; - address public _deployer = address(0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f); + address public _deployer = makeAddr("deployer"); + + address public arbitrumLzEndpoint = address(0x1a44076050125825900e736c501f859c50fE728c); + address public optimismLzEndpoint = address(0x1a44076050125825900e736c501f859c50fE728c); + address public mainnetLzEndpoint = address(0x1a44076050125825900e736c501f859c50fE728c); + + ERC20Mock public mainnetERC20; + L2YnERC20Upgradeable public optimismERC20; + L2YnERC20Upgradeable public arbitrumERC20; uint256 optimismFork; uint256 arbitrumFork; uint256 mainnetFork; + // uint256 holeskyFork; // uint256 fraxFork; // uint256 baseFork; @@ -39,14 +50,70 @@ contract CrossChainBaseTest is Test { // fraxFork = vm.createFork(vm.envString("FRAX_RPC_URL")); // baseFork = vm.createFork(vm.envString("BASE_RPC_URL")); - vm.selectFork(mainnetFork); - mainnetDeployer = new MultiChainDeployer(); + RateLimiter.RateLimitConfig[] memory _rateLimitConfigs = new RateLimiter.RateLimitConfig[](1); + _rateLimitConfigs[0] = RateLimiter.RateLimitConfig({dstEid: uint32(1), limit: 1 ether, window: 1 days}); - vm.selectFork(optimismFork); - optimismDeployer = new MultiChainDeployer(); + vm.startPrank(_deployer); - vm.selectFork(arbitrumFork); - arbitrumDeployer = new MultiChainDeployer(); + { + vm.selectFork(mainnetFork); + mainnetDeployer = new MultiChainDeployer{salt: "SALT"}(); + mainnetERC20 = new ERC20Mock("Test Token", "TEST"); + address mainnetOFTAdapterImpl = + address(new L1YnOFTAdapterUpgradeable(address(mainnetERC20), mainnetLzEndpoint)); + mainnetOFTAdapter = L1YnOFTAdapterUpgradeable( + address(new TransparentUpgradeableProxy(mainnetOFTAdapterImpl, _deployer, "")) + ); + mainnetOFTAdapter.initialize(_deployer, _rateLimitConfigs); + } + + { + vm.selectFork(optimismFork); + optimismDeployer = new MultiChainDeployer{salt: "SALT"}(); + bytes32 optimismERC20Salt = createSalt(_deployer, "ERC20"); + bytes32 optimismERC20ProxySalt = createSalt(_deployer, "ERC20Proxy"); + optimismERC20 = L2YnERC20Upgradeable( + optimismDeployer.deployL2YnERC20( + optimismERC20Salt, optimismERC20ProxySalt, "Test Token", "TEST", _deployer + ) + ); + bytes32 optimismOFTAdapterSalt = createSalt(_deployer, "OFTAdapter"); + bytes32 optimismOFTAdapterProxySalt = createSalt(_deployer, "OFTAdapterProxy"); + optimismOFTAdapter = L2YnOFTAdapterUpgradeable( + optimismDeployer.deployL2YnOFTAdapter( + optimismOFTAdapterSalt, + optimismOFTAdapterProxySalt, + address(optimismERC20), + optimismLzEndpoint, + _deployer, + _rateLimitConfigs + ) + ); + } + + { + vm.selectFork(arbitrumFork); + arbitrumDeployer = new MultiChainDeployer{salt: "SALT"}(); + bytes32 arbitrumERC20Salt = createSalt(_deployer, "ERC20"); + bytes32 arbitrumERC20ProxySalt = createSalt(_deployer, "ERC20Proxy"); + arbitrumERC20 = L2YnERC20Upgradeable( + arbitrumDeployer.deployL2YnERC20( + arbitrumERC20Salt, arbitrumERC20ProxySalt, "Test Token", "TEST", _deployer + ) + ); + bytes32 arbitrumOFTAdapterSalt = createSalt(_deployer, "OFTAdapter"); + bytes32 arbitrumOFTAdapterProxySalt = createSalt(_deployer, "OFTAdapterProxy"); + arbitrumOFTAdapter = L2YnOFTAdapterUpgradeable( + arbitrumDeployer.deployL2YnOFTAdapter( + arbitrumOFTAdapterSalt, + arbitrumOFTAdapterProxySalt, + address(arbitrumERC20), + arbitrumLzEndpoint, + _deployer, + _rateLimitConfigs + ) + ); + } // vm.selectFork(baseFork); // baseDeployer = new MultiChainDeployer(); @@ -54,26 +121,10 @@ contract CrossChainBaseTest is Test { // vm.selectFork(fraxFork); // fraxDeployer = new MultiChainDeployer(); - bytes memory contractByteCode = type(L1YnOFTAdapterUpgradeable).creationCode; - - // create salt where first 20 bytes matches the deployer address - bytes32 salt = createSalt(_deployer); - - RateLimiter.RateLimitConfig[] memory _rateLimitConfigs = new RateLimiter.RateLimitConfig[](1); - - RateLimiter.RateLimitConfig memory limitConfig = - RateLimiter.RateLimitConfig({dstEid: uint32(1), limit: 1 ether, window: 1 days}); - - _rateLimitConfigs[0] = limitConfig; - - vm.selectFork(mainnetFork); - vm.startPrank(_deployer); - l1OFTAdapter = - L1YnOFTAdapterUpgradeable(mainnetDeployer.deployOFTAdapter(salt, contractByteCode, _rateLimitConfigs)); vm.stopPrank(); } - function createSalt(address deployerAddress) public pure returns (bytes32 _salt) { - _salt = bytes32(abi.encodePacked(bytes20(deployerAddress), bytes12("testing_test"))); + function createSalt(address deployerAddress, string memory label) public pure returns (bytes32 _salt) { + _salt = bytes32(abi.encodePacked(bytes20(deployerAddress), bytes12(keccak256(bytes(label))))); } } diff --git a/test/MultiChainDeployer.t.sol b/test/MultiChainDeployer.t.sol index 1f5db3b..e14e70d 100644 --- a/test/MultiChainDeployer.t.sol +++ b/test/MultiChainDeployer.t.sol @@ -10,5 +10,13 @@ import {L2YnOFTAdapterUpgradeable} from "@adapters/L2YnOFTAdapterUpgradeable.sol import {RateLimiter} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/utils/RateLimiter.sol"; contract Test_MultiChainDeployer is CrossChainBaseTest { - function test_l1Deployment() public {} + function test_Deployment() public view { + assertEq(address(arbitrumDeployer), address(optimismDeployer)); + assertNotEq(address(mainnetERC20), address(0)); + assertNotEq(address(mainnetOFTAdapter), address(0)); + assertNotEq(address(arbitrumERC20), address(0)); + assertNotEq(address(arbitrumOFTAdapter), address(0)); + assertEq(address(arbitrumERC20), address(optimismERC20)); + assertEq(address(arbitrumOFTAdapter), address(optimismOFTAdapter)); + } }