From c80ceccd3b0f9b7c688cdc452e4f9dbee97975c5 Mon Sep 17 00:00:00 2001 From: lmcorbalan Date: Mon, 2 Sep 2024 13:03:42 -0300 Subject: [PATCH 01/21] feat: initial commit --- src/InterchainCreate2FactoryIsm.sol | 39 +++ src/InterchainCreate2FactoryRouter.sol | 346 +++++++++++++++++++ src/libs/InterchainCreate2FactoryMessage.sol | 63 ++++ 3 files changed, 448 insertions(+) create mode 100644 src/InterchainCreate2FactoryIsm.sol create mode 100644 src/InterchainCreate2FactoryRouter.sol create mode 100644 src/libs/InterchainCreate2FactoryMessage.sol diff --git a/src/InterchainCreate2FactoryIsm.sol b/src/InterchainCreate2FactoryIsm.sol new file mode 100644 index 0000000..eeded1d --- /dev/null +++ b/src/InterchainCreate2FactoryIsm.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +// ============ Internal Imports ============ + +// ============ External Imports ============ +import { AbstractRoutingIsm } from "@hyperlane-xyz/isms/routing/AbstractRoutingIsm.sol"; +import { IMailbox } from "@hyperlane-xyz/interfaces/IMailbox.sol"; +import { IInterchainSecurityModule } from "@hyperlane-xyz/interfaces/IInterchainSecurityModule.sol"; +import { Message } from "@hyperlane-xyz/libs/Message.sol"; +import { InterchainCreate2FactoryMessage } from "./libs/InterchainCreate2FactoryMessage.sol"; + +/** + * @title InterchainCreate2FactoryIsm + */ +contract InterchainCreate2FactoryIsm is AbstractRoutingIsm { + IMailbox private immutable mailbox; + + // ============ Constructor ============ + constructor(address _mailbox) { + mailbox = IMailbox(_mailbox); + } + + // ============ Public Functions ============ + + /** + * @notice Returns the ISM responsible for verifying _message + * @param _message Formatted Hyperlane message (see Message.sol). + * @return module The ISM to use to verify _message + */ + function route(bytes calldata _message) public view virtual override returns (IInterchainSecurityModule) { + address _ism = InterchainCreate2FactoryMessage.ism(Message.body(_message)); + if (_ism == address(0)) { + return IInterchainSecurityModule(address(mailbox.defaultIsm())); + } else { + return IInterchainSecurityModule(_ism); + } + } +} diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol new file mode 100644 index 0000000..b239f67 --- /dev/null +++ b/src/InterchainCreate2FactoryRouter.sol @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +// ============ Internal Imports ============ +import { InterchainCreate2FactoryMessage } from "./libs/InterchainCreate2FactoryMessage.sol"; + +// ============ External Imports ============ +import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; +import { StandardHookMetadata } from "@hyperlane-xyz/hooks/libs/StandardHookMetadata.sol"; +import { EnumerableMapExtended } from "@hyperlane-xyz/libs/EnumerableMapExtended.sol"; +import { Router } from "@hyperlane-xyz/client/Router.sol"; +import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol"; +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +/* + * @title A contract that allows accounts on chain A to deploy contracts on chain B. + */ +contract InterchainCreate2FactoryRouter is Router { + // ============ Libraries ============ + + using TypeCasts for address; + using TypeCasts for bytes32; + + // ============ Constants ============ + + // ============ Public Storage ============ + mapping(uint32 => bytes32) public isms; + + // ============ Upgrade Gap ============ + + uint256[47] private __GAP; + + // ============ Events ============ + + /** + * @notice Emitted when a default ISM is set for a remote domain + * @param domain The remote domain + * @param ism The address of the remote ISM + */ + event RemoteIsmEnrolled(uint32 indexed domain, bytes32 ism); + + event RemoteDeployDispatched(uint32 indexed destination, address indexed owner, bytes32 router, bytes32 ism); + + event Deployed(bytes32 indexed bytecodeHash, bytes32 indexed salt, address indexed deployedAddress); + + // ============ Constructor ============ + + constructor(address _mailbox) Router(_mailbox) { } + + // ============ Initializers ============ + + /** + * @notice Initializes the contract with HyperlaneConnectionClient contracts + * @param _customHook used by the Router to set the hook to override with + * @param _interchainSecurityModule The address of the local ISM contract + * @param _owner The address with owner privileges + */ + function initialize(address _customHook, address _interchainSecurityModule, address _owner) external initializer { + _MailboxClient_initialize(_customHook, _interchainSecurityModule, _owner); + } + + /** + * @notice Registers the address of remote InterchainAccountRouter + * and ISM contracts to use as a default when making interchain calls + * @param _destination The remote domain + * @param _router The address of the remote InterchainAccountRouter + * @param _ism The address of the remote ISM + */ + function enrollRemoteRouterAndIsm(uint32 _destination, bytes32 _router, bytes32 _ism) external onlyOwner { + _enrollRemoteRouterAndIsm(_destination, _router, _ism); + } + + /** + * @notice Registers the address of remote InterchainAccountRouters + * and ISM contracts to use as defaults when making interchain calls + * @param _destinations The remote domains + * @param _routers The address of the remote InterchainAccountRouters + * @param _isms The address of the remote ISMs + */ + function enrollRemoteRouterAndIsms( + uint32[] calldata _destinations, + bytes32[] calldata _routers, + bytes32[] calldata _isms + ) + external + onlyOwner + { + require(_destinations.length == _routers.length && _destinations.length == _isms.length, "length mismatch"); + for (uint256 i = 0; i < _destinations.length; i++) { + _enrollRemoteRouterAndIsm(_destinations[i], _routers[i], _isms[i]); + } + } + + // ============ External Functions ============ + + // TODo - review params order + function deployContract( + uint32 _destination, + bytes memory _bytecode, + bytes32 _salt + ) + external + payable + returns (bytes32) + { + bytes32 _router = routers(_destination); + bytes32 _ism = isms[_destination]; + bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, new bytes(0)); + + return _dispatchMessage(_destination, _router, _ism, _body); + } + + // TODo - review params order + function deployContract( + uint32 _destination, + bytes memory _bytecode, + bytes32 _salt, + bytes memory _hookMetadata + ) + external + payable + returns (bytes32) + { + bytes32 _router = routers(_destination); + bytes32 _ism = isms[_destination]; + bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, new bytes(0)); + + return _dispatchMessageWithMetadata(_destination, _router, _ism, _body, _hookMetadata); + } + + function deployContractAndInit( + uint32 _destination, + bytes memory _bytecode, + bytes32 _salt, + bytes memory _initCode + ) + external + payable + returns (bytes32) + { + bytes32 _router = routers(_destination); + bytes32 _ism = isms[_destination]; + bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); + + return _dispatchMessage(_destination, _router, _ism, _body); + } + + function deployContractAndInit( + uint32 _destination, + bytes memory _bytecode, + bytes32 _salt, + bytes memory _initCode, + bytes memory _hookMetadata + ) + external + payable + returns (bytes32) + { + bytes32 _router = routers(_destination); + bytes32 _ism = isms[_destination]; + bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); + + return _dispatchMessageWithMetadata(_destination, _router, _ism, _body, _hookMetadata); + } + + /** + * @notice Returns the gas payment required to dispatch a message to the given domain's router. + * @param _destination The domain of the destination router. + * @return _gasPayment Payment computed by the registered hooks via MailboxClient. + */ + function quoteGasPayment(uint32 _destination) external view returns (uint256 _gasPayment) { + return _quoteDispatch(_destination, ""); + } + + /** + * @notice Returns the gas payment required to dispatch a given messageBody to the given domain's router with gas + * limit override. + * @param _destination The domain of the destination router. + * @param _messageBody The message body to be dispatched. + * @param gasLimit The gas limit to override with. + */ + function quoteGasPayment( + uint32 _destination, + bytes calldata _messageBody, + uint256 gasLimit + ) + external + view + returns (uint256 _gasPayment) + { + bytes32 _router = _mustHaveRemoteRouter(_destination); + return + mailbox.quoteDispatch(_destination, _router, _messageBody, StandardHookMetadata.overrideGasLimit(gasLimit)); + } + + // ============ Public Functions ============ + + function deployContractWithOverrides( + uint32 _destination, + bytes32 _router, + bytes32 _ism, + bytes memory _bytecode, + bytes32 _salt + ) + public + payable + returns (bytes32) + { + bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, new bytes(0)); + + return _dispatchMessage(_destination, _router, _ism, _body); + } + + function deployContractAndInitWithOverrides( + uint32 _destination, + bytes32 _router, + bytes32 _ism, + bytes memory _bytecode, + bytes32 _salt, + bytes memory _initCode + ) + public + payable + returns (bytes32) + { + bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); + + return _dispatchMessage(_destination, _router, _ism, _body); + } + + // ============ Internal Functions ============ + + function _handle(uint32, bytes32, bytes calldata _message) internal override { + (bytes32 _sender, bytes32 _ism, bytes32 _salt, bytes memory _bytecode, bytes memory _initCode) = + InterchainCreate2FactoryMessage.decode(_message); + + address deployedAddress = _deploy(_bytecode, _getSalt(_sender, _salt)); + + if (_initCode.length > 0) { + // solhint-disable-next-line avoid-low-level-calls + (bool success,) = deployedAddress.call(_initCode); + require(success, "failed to init"); + } + } + + /** + * @notice Overrides Router._enrollRemoteRouter to also enroll a default ISM + * @param _destination The remote domain + * @param _address The address of the remote InterchainAccountRouter + * @dev Sets the default ISM to the zero address + */ + function _enrollRemoteRouter(uint32 _destination, bytes32 _address) internal override { + _enrollRemoteRouterAndIsm(_destination, _address, bytes32(0)); + } + + // ============ Private Functions ============ + + /** + * @notice Registers the address of a remote ISM contract to use as default + * @param _destination The remote domain + * @param _ism The address of the remote ISM + */ + function _enrollRemoteIsm(uint32 _destination, bytes32 _ism) private { + isms[_destination] = _ism; + emit RemoteIsmEnrolled(_destination, _ism); + } + + /** + * @notice Registers the address of remote InterchainAccountRouter + * and ISM contracts to use as a default when making interchain calls + * @param _destination The remote domain + * @param _router The address of the remote InterchainAccountRouter + * @param _ism The address of the remote ISM + */ + function _enrollRemoteRouterAndIsm(uint32 _destination, bytes32 _router, bytes32 _ism) private { + require( + routers(_destination) == bytes32(0) && isms[_destination] == bytes32(0), + "router and ISM defaults are immutable once set" + ); + Router._enrollRemoteRouter(_destination, _router); + _enrollRemoteIsm(_destination, _ism); + } + + /** + * @notice Dispatches an InterchainAccountMessage to the remote router + * @param _destination The remote domain + * @param _router The address of the remote InterchainAccountRouter + * @param _ism The address of the remote ISM + * @param _body The InterchainAccountMessage body + */ + function _dispatchMessage( + uint32 _destination, + bytes32 _router, + bytes32 _ism, + bytes memory _body + ) + private + returns (bytes32) + { + require(_router != bytes32(0), "no router specified for destination"); + emit RemoteDeployDispatched(_destination, msg.sender, _router, _ism); + return mailbox.dispatch{ value: msg.value }(_destination, _router, _body); + } + + /** + * @notice Dispatches an InterchainAccountMessage to the remote router with hook metadata + * @param _destination The remote domain + * @param _router The address of the remote InterchainAccountRouter + * @param _ism The address of the remote ISM + * @param _body The InterchainAccountMessage body + * @param _hookMetadata The hook metadata to override with for the hook set by the owner + */ + function _dispatchMessageWithMetadata( + uint32 _destination, + bytes32 _router, + bytes32 _ism, + bytes memory _body, + bytes memory _hookMetadata + ) + private + returns (bytes32) + { + require(_router != bytes32(0), "no router specified for destination"); + emit RemoteDeployDispatched(_destination, msg.sender, _router, _ism); + return mailbox.dispatch{ value: msg.value }(_destination, _router, _body, _hookMetadata); + } + + /** + * @notice Returns the salt used to deploy an interchain account + * @param _sender The remote sender + * @param _senderSalt The salt used by the sender on the remote chain + * @return The CREATE2 salt used for deploying the contract + */ + function _getSalt(bytes32 _sender, bytes32 _senderSalt) private pure returns (bytes32) { + return keccak256(abi.encode(_sender, _senderSalt)); + } + + function _deploy(bytes memory _bytecode, bytes32 _salt) internal returns (address deployedAddress) { + require(_bytecode.length > 0, "empty bytecode"); + + deployedAddress = Create2.deploy(0, _salt, _bytecode); + + emit Deployed(keccak256(_bytecode), _salt, deployedAddress); + } +} diff --git a/src/libs/InterchainCreate2FactoryMessage.sol b/src/libs/InterchainCreate2FactoryMessage.sol new file mode 100644 index 0000000..af67891 --- /dev/null +++ b/src/libs/InterchainCreate2FactoryMessage.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +// ============ External Imports ============ +import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; + +/** + * Format of message: + * [ 0: 32] sender + * [ 32: 64] ISM + * [ 64: 96] salt + * [ 96: ????] bytecode + * [ ????:????] initCode + */ +library InterchainCreate2FactoryMessage { + using TypeCasts for bytes32; + + /** + * @notice Returns formatted (packed) InterchainCreate2FactoryMessage + * @dev This function should only be used in memory message construction. + * @param _sender The sender of the message + * @param _salt The address of the remote ISM + * @param _ism The address of the remote ISM + * @param _bytecode The bytecode + * @param _initCode The initCode + * @return Formatted message body + */ + function encode( + address _sender, + bytes32 _ism, + bytes32 _salt, + bytes memory _bytecode, + bytes memory _initCode + ) + internal + pure + returns (bytes memory) + { + return abi.encode(TypeCasts.addressToBytes32(_sender), _ism, _salt, _bytecode, _initCode); + } + + /** + * @notice Parses and returns the calls from the provided message + * @param _message The interchain account message + * @return The array of calls + */ + function decode(bytes calldata _message) + internal + pure + returns (bytes32, bytes32, bytes32, bytes memory, bytes memory) + { + return abi.decode(_message, (bytes32, bytes32, bytes32, bytes, bytes)); + } + + /** + * @notice Parses and returns the ISM address from the provided message + * @param _message The interchain account message + * @return The ISM encoded in the message + */ + function ism(bytes calldata _message) internal pure returns (address) { + return address(bytes20(_message[44:64])); + } +} From c4006b174e3f27882fc6385874ec5f9a74febe75 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Tue, 3 Sep 2024 09:58:48 -0300 Subject: [PATCH 02/21] CI --- .github/workflows/ci.yml | 32 ++++++++++-------- .github/workflows/use-template.yml | 52 ------------------------------ 2 files changed, 19 insertions(+), 65 deletions(-) delete mode 100644 .github/workflows/use-template.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7550749..06ce1d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,14 +21,16 @@ jobs: - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" - - name: "Install Bun" - uses: "oven-sh/setup-bun@v1" + - name: Set Node.js + uses: actions/setup-node@v3 - - name: "Install the Node.js dependencies" - run: "bun install" + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install # will run `yarn install` command - name: "Lint the code" - run: "bun run lint" + run: "yarn lint" - name: "Add lint summary" run: | @@ -44,11 +46,13 @@ jobs: - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" - - name: "Install Bun" - uses: "oven-sh/setup-bun@v1" + - name: Set Node.js + uses: actions/setup-node@v3 - - name: "Install the Node.js dependencies" - run: "bun install" + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install # will run `yarn install` command - name: "Build the contracts and print their size" run: "forge build --sizes" @@ -68,11 +72,13 @@ jobs: - name: "Install Foundry" uses: "foundry-rs/foundry-toolchain@v1" - - name: "Install Bun" - uses: "oven-sh/setup-bun@v1" + - name: Set Node.js + uses: actions/setup-node@v3 - - name: "Install the Node.js dependencies" - run: "bun install" + - name: Run install + uses: borales/actions-yarn@v4 + with: + cmd: install # will run `yarn install` command - name: "Show the Foundry config" run: "forge config" diff --git a/.github/workflows/use-template.yml b/.github/workflows/use-template.yml deleted file mode 100644 index 183b177..0000000 --- a/.github/workflows/use-template.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: "Create" - -# The workflow will run when the "Use this template" button is used -on: - push: - -jobs: - create: - # We only run this action when the repository isn't the template repository. References: - # - https://docs.github.com/en/actions/learn-github-actions/contexts - # - https://docs.github.com/en/actions/learn-github-actions/expressions - if: ${{ !github.event.repository.is_template }} - permissions: "write-all" - runs-on: "ubuntu-latest" - steps: - - name: "Check out the repo" - uses: "actions/checkout@v4" - - - name: "Update package.json" - env: - GITHUB_REPOSITORY_DESCRIPTION: ${{ github.event.repository.description }} - run: - ./.github/scripts/rename.sh "$GITHUB_REPOSITORY" "$GITHUB_REPOSITORY_OWNER" "$GITHUB_REPOSITORY_DESCRIPTION" - - - name: "Add rename summary" - run: | - echo "## Commit result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY - - - name: "Remove files not needed in the user's copy of the template" - run: | - rm -f "./.github/FUNDING.yml" - rm -f "./.github/scripts/rename.sh" - rm -f "./.github/workflows/create.yml" - - - name: "Add remove summary" - run: | - echo "## Remove result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY - - - name: "Update commit" - uses: "stefanzweifel/git-auto-commit-action@v4" - with: - commit_message: "feat: initial commit" - commit_options: "--amend" - push_options: "--force" - skip_fetch: true - - - name: "Add commit summary" - run: | - echo "## Commit result" >> $GITHUB_STEP_SUMMARY - echo "✅ Passed" >> $GITHUB_STEP_SUMMARY From 3bdd45db72a4060f5de9e0fee4da4265b15b04a3 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Wed, 4 Sep 2024 14:40:04 -0300 Subject: [PATCH 03/21] Remove ism enrollment and change quoteGasPayment --- src/InterchainCreate2FactoryRouter.sol | 240 +++++++------------------ 1 file changed, 61 insertions(+), 179 deletions(-) diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol index b239f67..caefaaa 100644 --- a/src/InterchainCreate2FactoryRouter.sol +++ b/src/InterchainCreate2FactoryRouter.sol @@ -25,7 +25,6 @@ contract InterchainCreate2FactoryRouter is Router { // ============ Constants ============ // ============ Public Storage ============ - mapping(uint32 => bytes32) public isms; // ============ Upgrade Gap ============ @@ -33,14 +32,7 @@ contract InterchainCreate2FactoryRouter is Router { // ============ Events ============ - /** - * @notice Emitted when a default ISM is set for a remote domain - * @param domain The remote domain - * @param ism The address of the remote ISM - */ - event RemoteIsmEnrolled(uint32 indexed domain, bytes32 ism); - - event RemoteDeployDispatched(uint32 indexed destination, address indexed owner, bytes32 router, bytes32 ism); + event RemoteDeployDispatched(uint32 indexed destination, address indexed owner, uint32 _destination, bytes32 ism); event Deployed(bytes32 indexed bytecodeHash, bytes32 indexed salt, address indexed deployedAddress); @@ -60,96 +52,60 @@ contract InterchainCreate2FactoryRouter is Router { _MailboxClient_initialize(_customHook, _interchainSecurityModule, _owner); } - /** - * @notice Registers the address of remote InterchainAccountRouter - * and ISM contracts to use as a default when making interchain calls - * @param _destination The remote domain - * @param _router The address of the remote InterchainAccountRouter - * @param _ism The address of the remote ISM - */ - function enrollRemoteRouterAndIsm(uint32 _destination, bytes32 _router, bytes32 _ism) external onlyOwner { - _enrollRemoteRouterAndIsm(_destination, _router, _ism); - } - - /** - * @notice Registers the address of remote InterchainAccountRouters - * and ISM contracts to use as defaults when making interchain calls - * @param _destinations The remote domains - * @param _routers The address of the remote InterchainAccountRouters - * @param _isms The address of the remote ISMs - */ - function enrollRemoteRouterAndIsms( - uint32[] calldata _destinations, - bytes32[] calldata _routers, - bytes32[] calldata _isms - ) - external - onlyOwner - { - require(_destinations.length == _routers.length && _destinations.length == _isms.length, "length mismatch"); - for (uint256 i = 0; i < _destinations.length; i++) { - _enrollRemoteRouterAndIsm(_destinations[i], _routers[i], _isms[i]); - } - } - // ============ External Functions ============ - // TODo - review params order function deployContract( uint32 _destination, - bytes memory _bytecode, - bytes32 _salt + bytes32 _ism, + bytes32 _salt, + bytes memory _bytecode ) external payable returns (bytes32) { - bytes32 _router = routers(_destination); - bytes32 _ism = isms[_destination]; bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, new bytes(0)); - return _dispatchMessage(_destination, _router, _ism, _body); + return _dispatchMessage(_destination, _ism, _body, ""); } - // TODo - review params order function deployContract( uint32 _destination, - bytes memory _bytecode, + bytes32 _ism, bytes32 _salt, + bytes memory _bytecode, bytes memory _hookMetadata ) external payable returns (bytes32) { - bytes32 _router = routers(_destination); - bytes32 _ism = isms[_destination]; bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, new bytes(0)); - return _dispatchMessageWithMetadata(_destination, _router, _ism, _body, _hookMetadata); + return _dispatchMessage(_destination, _ism, _body, _hookMetadata); } function deployContractAndInit( uint32 _destination, - bytes memory _bytecode, + bytes32 _ism, bytes32 _salt, + bytes memory _bytecode, bytes memory _initCode ) external payable returns (bytes32) { - bytes32 _router = routers(_destination); - bytes32 _ism = isms[_destination]; bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); - return _dispatchMessage(_destination, _router, _ism, _body); + return _dispatchMessage(_destination, _ism, _body, ""); } function deployContractAndInit( uint32 _destination, - bytes memory _bytecode, + bytes32 _ism, bytes32 _salt, + bytes memory _bytecode, bytes memory _initCode, bytes memory _hookMetadata ) @@ -157,20 +113,9 @@ contract InterchainCreate2FactoryRouter is Router { payable returns (bytes32) { - bytes32 _router = routers(_destination); - bytes32 _ism = isms[_destination]; bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); - return _dispatchMessageWithMetadata(_destination, _router, _ism, _body, _hookMetadata); - } - - /** - * @notice Returns the gas payment required to dispatch a message to the given domain's router. - * @param _destination The domain of the destination router. - * @return _gasPayment Payment computed by the registered hooks via MailboxClient. - */ - function quoteGasPayment(uint32 _destination) external view returns (uint256 _gasPayment) { - return _quoteDispatch(_destination, ""); + return _dispatchMessage(_destination, _ism, _body, _hookMetadata); } /** @@ -178,152 +123,89 @@ contract InterchainCreate2FactoryRouter is Router { * limit override. * @param _destination The domain of the destination router. * @param _messageBody The message body to be dispatched. - * @param gasLimit The gas limit to override with. + * @param _hookMetadata The hook metadata to override with for the hook set by the owner */ function quoteGasPayment( uint32 _destination, - bytes calldata _messageBody, - uint256 gasLimit + bytes memory _messageBody, + bytes memory _hookMetadata ) external view returns (uint256 _gasPayment) { - bytes32 _router = _mustHaveRemoteRouter(_destination); - return - mailbox.quoteDispatch(_destination, _router, _messageBody, StandardHookMetadata.overrideGasLimit(gasLimit)); - } - - // ============ Public Functions ============ - - function deployContractWithOverrides( - uint32 _destination, - bytes32 _router, - bytes32 _ism, - bytes memory _bytecode, - bytes32 _salt - ) - public - payable - returns (bytes32) - { - bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, new bytes(0)); - return _dispatchMessage(_destination, _router, _ism, _body); + return _Router_quoteDispatch( + _destination,_messageBody, _hookMetadata, address(hook) + ); } - function deployContractAndInitWithOverrides( - uint32 _destination, - bytes32 _router, - bytes32 _ism, - bytes memory _bytecode, + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy} or {deployAndInit} by `sender`. + * Any change in the `bytecode`, `sender`, or `salt` will result in a new destination address. + */ + function deployedAddress( + address _sender, bytes32 _salt, - bytes memory _initCode - ) - public - payable - returns (bytes32) - { - bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); - - return _dispatchMessage(_destination, _router, _ism, _body); + bytes memory _bytecode + ) external view returns (address) { + return address( + uint160( + uint256( + keccak256( + abi.encodePacked( + hex"ff", + address(this), + _getSalt(TypeCasts.addressToBytes32(_sender), _salt), + keccak256(_bytecode) // init code hash + ) + ) + ) + ) + ); } // ============ Internal Functions ============ function _handle(uint32, bytes32, bytes calldata _message) internal override { - (bytes32 _sender, bytes32 _ism, bytes32 _salt, bytes memory _bytecode, bytes memory _initCode) = + (bytes32 _sender, , bytes32 _salt, bytes memory _bytecode, bytes memory _initCode) = InterchainCreate2FactoryMessage.decode(_message); - address deployedAddress = _deploy(_bytecode, _getSalt(_sender, _salt)); + address deployedAddress_ = _deploy(_bytecode, _getSalt(_sender, _salt)); if (_initCode.length > 0) { // solhint-disable-next-line avoid-low-level-calls - (bool success,) = deployedAddress.call(_initCode); + (bool success,) = deployedAddress_.call(_initCode); require(success, "failed to init"); } } - /** - * @notice Overrides Router._enrollRemoteRouter to also enroll a default ISM - * @param _destination The remote domain - * @param _address The address of the remote InterchainAccountRouter - * @dev Sets the default ISM to the zero address - */ - function _enrollRemoteRouter(uint32 _destination, bytes32 _address) internal override { - _enrollRemoteRouterAndIsm(_destination, _address, bytes32(0)); - } - - // ============ Private Functions ============ - - /** - * @notice Registers the address of a remote ISM contract to use as default - * @param _destination The remote domain - * @param _ism The address of the remote ISM - */ - function _enrollRemoteIsm(uint32 _destination, bytes32 _ism) private { - isms[_destination] = _ism; - emit RemoteIsmEnrolled(_destination, _ism); - } - - /** - * @notice Registers the address of remote InterchainAccountRouter - * and ISM contracts to use as a default when making interchain calls - * @param _destination The remote domain - * @param _router The address of the remote InterchainAccountRouter - * @param _ism The address of the remote ISM - */ - function _enrollRemoteRouterAndIsm(uint32 _destination, bytes32 _router, bytes32 _ism) private { - require( - routers(_destination) == bytes32(0) && isms[_destination] == bytes32(0), - "router and ISM defaults are immutable once set" - ); - Router._enrollRemoteRouter(_destination, _router); - _enrollRemoteIsm(_destination, _ism); - } - /** * @notice Dispatches an InterchainAccountMessage to the remote router * @param _destination The remote domain - * @param _router The address of the remote InterchainAccountRouter - * @param _ism The address of the remote ISM - * @param _body The InterchainAccountMessage body - */ - function _dispatchMessage( - uint32 _destination, - bytes32 _router, - bytes32 _ism, - bytes memory _body - ) - private - returns (bytes32) - { - require(_router != bytes32(0), "no router specified for destination"); - emit RemoteDeployDispatched(_destination, msg.sender, _router, _ism); - return mailbox.dispatch{ value: msg.value }(_destination, _router, _body); - } - - /** - * @notice Dispatches an InterchainAccountMessage to the remote router with hook metadata - * @param _destination The remote domain - * @param _router The address of the remote InterchainAccountRouter * @param _ism The address of the remote ISM - * @param _body The InterchainAccountMessage body + * @param _messageBody The InterchainAccountMessage body * @param _hookMetadata The hook metadata to override with for the hook set by the owner */ - function _dispatchMessageWithMetadata( + function _dispatchMessage( uint32 _destination, - bytes32 _router, bytes32 _ism, - bytes memory _body, + bytes memory _messageBody, bytes memory _hookMetadata + ) private returns (bytes32) { - require(_router != bytes32(0), "no router specified for destination"); - emit RemoteDeployDispatched(_destination, msg.sender, _router, _ism); - return mailbox.dispatch{ value: msg.value }(_destination, _router, _body, _hookMetadata); + emit RemoteDeployDispatched(_destination, msg.sender, _destination, _ism); + + return _Router_dispatch( + _destination, + msg.value, + _messageBody, + _hookMetadata, + address(hook) + ); } /** @@ -336,11 +218,11 @@ contract InterchainCreate2FactoryRouter is Router { return keccak256(abi.encode(_sender, _senderSalt)); } - function _deploy(bytes memory _bytecode, bytes32 _salt) internal returns (address deployedAddress) { + function _deploy(bytes memory _bytecode, bytes32 _salt) internal returns (address deployedAddress_) { require(_bytecode.length > 0, "empty bytecode"); - deployedAddress = Create2.deploy(0, _salt, _bytecode); + deployedAddress_ = Create2.deploy(0, _salt, _bytecode); - emit Deployed(keccak256(_bytecode), _salt, deployedAddress); + emit Deployed(keccak256(_bytecode), _salt, deployedAddress_); } } From 94f981eab4d98188f4535734525e7896ddf3fa74 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Wed, 4 Sep 2024 14:40:22 -0300 Subject: [PATCH 04/21] Add InterchainCreate2FactoryRouter tests --- test/InterchainCreate2FactoryRouter.t.sol | 660 ++++++++++++++++++++++ 1 file changed, 660 insertions(+) create mode 100644 test/InterchainCreate2FactoryRouter.t.sol diff --git a/test/InterchainCreate2FactoryRouter.t.sol b/test/InterchainCreate2FactoryRouter.t.sol new file mode 100644 index 0000000..24c3dfe --- /dev/null +++ b/test/InterchainCreate2FactoryRouter.t.sol @@ -0,0 +1,660 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import { Test } from "forge-std/src/Test.sol"; +import { console2 } from "forge-std/src/console2.sol"; + +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; + +import {StandardHookMetadata} from "@hyperlane-xyz/hooks/libs/StandardHookMetadata.sol"; +import {MockMailbox} from "@hyperlane-xyz/mock/MockMailbox.sol"; +import {MockHyperlaneEnvironment} from "@hyperlane-xyz/mock/MockHyperlaneEnvironment.sol"; +import {TypeCasts} from "@hyperlane-xyz/libs/TypeCasts.sol"; +import {IInterchainSecurityModule} from "@hyperlane-xyz/interfaces/IInterchainSecurityModule.sol"; +import {TestInterchainGasPaymaster} from "@hyperlane-xyz/test/TestInterchainGasPaymaster.sol"; +import {IPostDispatchHook} from "@hyperlane-xyz/interfaces/hooks/IPostDispatchHook.sol"; +import {TestIsm} from "@hyperlane-xyz/test/TestIsm.sol"; + +import {InterchainCreate2FactoryRouter} from "src/InterchainCreate2FactoryRouter.sol"; +import {InterchainCreate2FactoryIsm} from "src/InterchainCreate2FactoryIsm.sol"; +import { InterchainCreate2FactoryMessage } from "src/libs/InterchainCreate2FactoryMessage.sol"; + +contract SomeContract { + uint256 public counter; + + event SomeEvent(uint256 counter); + function someFunction() external { + counter++; + emit SomeEvent(counter); + } +} + +contract FailingIsm is IInterchainSecurityModule { + string public failureMessage; + uint8 public moduleType; + + constructor(string memory _failureMessage) { + failureMessage = _failureMessage; + } + + function verify( + bytes calldata, + bytes calldata + ) external view returns (bool) { + revert(failureMessage); + } +} + +contract InterchainCreate2FactoryRouterBase is Test { + using TypeCasts for address; + + event Deployed(bytes32 indexed bytecodeHash, bytes32 indexed salt, address indexed deployedAddress); + event SomeEvent(uint256 counter); + + MockHyperlaneEnvironment internal environment; + + uint32 internal origin = 1; + uint32 internal destination = 2; + + TestInterchainGasPaymaster internal igp; + InterchainCreate2FactoryIsm internal ism; + InterchainCreate2FactoryRouter internal originRouter; + InterchainCreate2FactoryRouter internal destinationRouter; + + TestIsm internal testIsm; + bytes32 internal testIsmB32; + bytes32 internal originRouterB32; + bytes32 internal destinationRouterB32; + + uint256 gasPaymentQuote; + uint256 internal constant GAS_LIMIT_OVERRIDE = 60000; + + address internal admin = makeAddr("admin"); + address internal owner = makeAddr("owner"); + // address internal sender = makeAddr("sender"); + + function deployProxiedRouter( + MockMailbox _mailbox, + IPostDispatchHook _customHook, + IInterchainSecurityModule _ism, + address _owner + ) public returns (InterchainCreate2FactoryRouter) { + InterchainCreate2FactoryRouter implementation = new InterchainCreate2FactoryRouter( + address(_mailbox) + ); + + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(implementation), + admin, + abi.encodeWithSelector( + InterchainCreate2FactoryRouter.initialize.selector, + address(_customHook), + address(_ism), + _owner + ) + ); + + return InterchainCreate2FactoryRouter(address(proxy)); + } + + function setUp() public virtual { + environment = new MockHyperlaneEnvironment(origin, destination); + + igp = new TestInterchainGasPaymaster(); + gasPaymentQuote = igp.quoteGasPayment( + destination, + igp.getDefaultGasUsage() + ); + + ism = new InterchainCreate2FactoryIsm( + address(environment.mailboxes(destination)) + ); + + testIsm = new TestIsm(); + + originRouter = deployProxiedRouter( + environment.mailboxes(origin), + environment.igps(destination), + ism, + owner + ); + destinationRouter = deployProxiedRouter( + environment.mailboxes(destination), + environment.igps(destination), + ism, + owner + ); + + environment.mailboxes(origin).setDefaultHook(address(igp)); + + originRouterB32 = TypeCasts.addressToBytes32(address(originRouter)); + destinationRouterB32 = TypeCasts.addressToBytes32(address(destinationRouter)); + testIsmB32 = TypeCasts.addressToBytes32(address(testIsm)); + } + + receive() external payable {} +} + +contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBase { + using TypeCasts for address; + + modifier enrollRouters() { + vm.startPrank(owner); + originRouter.enrollRemoteRouter( + destination, + destinationRouterB32 + ); + + destinationRouter.enrollRemoteRouter( + origin, + originRouterB32 + ); + + vm.stopPrank(); + _; +} + + + function testFuzz_enrollRemoteRouters( + uint8 count, + uint32 domain, + bytes32 router + ) public { + vm.assume(count > 0 && count < uint256(router) && count < domain); + + // arrange + // count - # of domains and routers + uint32[] memory domains = new uint32[](count); + bytes32[] memory routers = new bytes32[](count); + for (uint256 i = 0; i < count; i++) { + domains[i] = domain - uint32(i); + routers[i] = bytes32(uint256(router) - i); + } + + // act + vm.prank(owner); + originRouter.enrollRemoteRouters(domains, routers); + + // assert + uint32[] memory actualDomains = originRouter.domains(); + assertEq(actualDomains.length, domains.length); + assertEq(abi.encode(originRouter.domains()), abi.encode(domains)); + + for (uint256 i = 0; i < count; i++) { + bytes32 actualRouter = originRouter.routers(domains[i]); + + assertEq(actualRouter, routers[i]); + assertEq(actualDomains[i], domains[i]); + } + } + + function test_quoteGasPayment() public enrollRouters { + // arrange + bytes memory messageBody = InterchainCreate2FactoryMessage.encode( + address(1), + TypeCasts.addressToBytes32(address(0)), + "", + new bytes(0), + new bytes(0) + ); + + // assert + assertEq(originRouter.quoteGasPayment(destination, messageBody, new bytes(0)), gasPaymentQuote); + } + + function test_quoteGasPayment_gasLimitOverride() public enrollRouters { + // arrange + bytes memory messageBody = InterchainCreate2FactoryMessage.encode( + address(1), + TypeCasts.addressToBytes32(address(0)), + "", + new bytes(0), + new bytes(0) + ); + + bytes memory hookMetadata = StandardHookMetadata.overrideGasLimit(GAS_LIMIT_OVERRIDE); + + // assert + assertEq( + originRouter.quoteGasPayment(destination, messageBody, hookMetadata), + igp.quoteGasPayment(destination, GAS_LIMIT_OVERRIDE) + ); + } + + function assertContractDeployed(address _sender, bytes32 _salt, bytes memory _bytecode, address _ism) private { + address expectedAddress = destinationRouter.deployedAddress(_sender, _salt, _bytecode); + + assertFalse(Address.isContract(expectedAddress)); + + vm.expectCall(address(_ism), abi.encodeWithSelector(TestIsm.verify.selector)); + + vm.expectEmit(true, true, true, true, address(destinationRouter)); + emit Deployed(keccak256(_bytecode), keccak256(abi.encode(_sender, _salt)), expectedAddress); + environment.processNextPendingMessage(); + + assertTrue(Address.isContract(expectedAddress)); + + uint256 counterBefore = SomeContract(expectedAddress).counter(); + + vm.expectEmit(true, true, true, true, expectedAddress); + emit SomeEvent(counterBefore+1); + SomeContract(expectedAddress).someFunction(); + } + + function assertContractDeployedAndInit(address _sender, bytes32 _salt, bytes memory _bytecode, address _ism) private { + address expectedAddress = destinationRouter.deployedAddress(_sender, _salt, _bytecode); + + assertFalse(Address.isContract(expectedAddress)); + + vm.expectCall(address(_ism), abi.encodeWithSelector(TestIsm.verify.selector)); + + vm.expectEmit(true, true, true, true, address(destinationRouter)); + emit Deployed(keccak256(_bytecode), keccak256(abi.encode(_sender, _salt)), expectedAddress); + + vm.expectEmit(true, true, true, true, expectedAddress); + emit SomeEvent(1); + + environment.processNextPendingMessage(); + + assertTrue(Address.isContract(expectedAddress)); + + uint256 counterBefore = SomeContract(expectedAddress).counter(); + + vm.expectEmit(true, true, true, true, expectedAddress); + emit SomeEvent(counterBefore+1); + SomeContract(expectedAddress).someFunction(); + } + + function assertIgpPayment( + uint256 balanceBefore, + uint256 balanceAfter, + uint256 gasLimit + ) private view { + uint256 expectedGasPayment = gasLimit * igp.gasPrice(); + assertEq(balanceBefore - balanceAfter, expectedGasPayment); + assertEq(address(igp).balance, expectedGasPayment); + } + + function assumeSender(address _sender) internal view{ + vm.assume(_sender != address(0) && _sender != admin && !Address.isContract(_sender)); + assumeNotPrecompile(_sender); + } + + function testFuzz_deployContract_no_router_enrolled(address sender, bytes32 salt) public { + assumeSender(sender); + + // arrange + vm.deal(sender, gasPaymentQuote); + + // act + bytes memory bytecode = type(SomeContract).creationCode; + vm.prank(sender); + vm.expectRevert("No router enrolled for domain: 2"); + originRouter.deployContract{value: gasPaymentQuote}( + destination, + "", + salt, + bytecode + ); + } + + function testFuzz_deployContract_defaultISM(address sender, bytes32 salt) public enrollRouters { + assumeSender(sender); + + // arrange + vm.deal(sender, gasPaymentQuote); + + uint256 balanceBefore = address(sender).balance; + + // act + bytes memory bytecode = type(SomeContract).creationCode; + vm.prank(sender); + originRouter.deployContract{value: gasPaymentQuote}( + destination, + "", + salt, + bytecode + ); + + // assert + uint256 balanceAfter = address(sender).balance; + address _ism = address(environment.mailboxes(destination).defaultIsm()); + assertContractDeployed(sender, salt, type(SomeContract).creationCode, _ism); + assertIgpPayment(balanceBefore, balanceAfter, igp.getDefaultGasUsage()); + } + + function testFuzz_deployContractAndInit_defaultISM(address sender, bytes32 salt) public enrollRouters { + assumeSender(sender); + + // arrange + vm.deal(sender, gasPaymentQuote); + + uint256 balanceBefore = address(sender).balance; + + // act + bytes memory bytecode = type(SomeContract).creationCode; + bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); + + vm.prank(sender); + originRouter.deployContractAndInit{value: gasPaymentQuote}( + destination, + "", + salt, + bytecode, + initCode + ); + + // assert + uint256 balanceAfter = address(sender).balance; + address _ism = address(environment.mailboxes(destination).defaultIsm()); + assertContractDeployedAndInit(sender, salt, type(SomeContract).creationCode, _ism); + assertIgpPayment(balanceBefore, balanceAfter, igp.getDefaultGasUsage()); + } + + function testFuzz_deployContract_defaultISM_customMetadata_forIgp(address sender, bytes32 salt, uint64 gasLimit, uint64 overpayment) public enrollRouters { + assumeSender(sender); + + // arrange + uint256 payment = gasLimit * igp.gasPrice() + overpayment; + vm.deal(sender, payment); + + bytes memory metadata = StandardHookMetadata.formatMetadata( + 0, + gasLimit, + sender, + "" + ); + + uint256 balanceBefore = address(sender).balance; + + // act + bytes memory bytecode = type(SomeContract).creationCode; + vm.prank(sender); + originRouter.deployContract{value: payment}( + destination, + "", + salt, + bytecode, + metadata + ); + + // assert + uint256 balanceAfter = address(sender).balance; + address _ism = address(environment.mailboxes(destination).defaultIsm()); + assertContractDeployed(sender, salt, type(SomeContract).creationCode, _ism); + assertIgpPayment(balanceBefore, balanceAfter, gasLimit); + } + + function testFuzz_deployContractAndInit_defaultISM_customMetadata_forIgp(address sender, bytes32 salt, uint64 gasLimit, uint64 overpayment) public enrollRouters { + assumeSender(sender); + + // arrange + uint256 payment = gasLimit * igp.gasPrice() + overpayment; + vm.deal(sender, payment); + + bytes memory metadata = StandardHookMetadata.formatMetadata( + 0, + gasLimit, + sender, + "" + ); + + uint256 balanceBefore = address(sender).balance; + + // act + bytes memory bytecode = type(SomeContract).creationCode; + bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); + + vm.prank(sender); + originRouter.deployContractAndInit{value: payment}( + destination, + "", + salt, + bytecode, + initCode, + metadata + ); + + // assert + uint256 balanceAfter = address(sender).balance; + address _ism = address(environment.mailboxes(destination).defaultIsm()); + assertContractDeployedAndInit(sender, salt, type(SomeContract).creationCode, _ism); + assertIgpPayment(balanceBefore, balanceAfter, gasLimit); + } + + function testFuzz_deployContract_defaultISM_reverts_underpayment(address sender, bytes32 salt, uint64 gasLimit, uint64 payment) public enrollRouters { + assumeSender(sender); + vm.assume(payment < gasLimit * igp.gasPrice()); + + // arrange + vm.deal(sender, payment); + + bytes memory metadata = StandardHookMetadata.formatMetadata( + 0, + gasLimit, + sender, + "" + ); + + // act + bytes memory bytecode = type(SomeContract).creationCode; + vm.prank(sender); + vm.expectRevert("IGP: insufficient interchain gas payment"); + originRouter.deployContract{value: payment}( + destination, + "", + salt, + bytecode, + metadata + ); + } + + function testFuzz_deployContractAndInit_defaultISM_reverts_underpayment(address sender, bytes32 salt, uint64 gasLimit, uint64 payment) public enrollRouters { + assumeSender(sender); + vm.assume(payment < gasLimit * igp.gasPrice()); + + // arrange + vm.deal(sender, payment); + + bytes memory metadata = StandardHookMetadata.formatMetadata( + 0, + gasLimit, + sender, + "" + ); + + // act + bytes memory bytecode = type(SomeContract).creationCode; + bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); + + vm.prank(sender); + vm.expectRevert("IGP: insufficient interchain gas payment"); + originRouter.deployContractAndInit{value: payment}( + destination, + "", + salt, + bytecode, + initCode, + metadata + ); + } + + function testFuzz_deployContract_paramISM(address sender, bytes32 salt) public enrollRouters { + assumeSender(sender); + + // arrange + vm.deal(sender, gasPaymentQuote); + + uint256 balanceBefore = address(sender).balance; + + // act + bytes memory bytecode = type(SomeContract).creationCode; + vm.prank(sender); + originRouter.deployContract{value: gasPaymentQuote}( + destination, + testIsmB32, + salt, + bytecode + ); + + // assert + uint256 balanceAfter = address(sender).balance; + assertContractDeployed(sender, salt, type(SomeContract).creationCode, address(testIsm)); + assertIgpPayment(balanceBefore, balanceAfter, igp.getDefaultGasUsage()); + } + + function testFuzz_deployContractAndInit_paramISM(address sender, bytes32 salt) public enrollRouters { + assumeSender(sender); + + // arrange + vm.deal(sender, gasPaymentQuote); + + uint256 balanceBefore = address(sender).balance; + + // act + bytes memory bytecode = type(SomeContract).creationCode; + bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); + + vm.prank(sender); + originRouter.deployContractAndInit{value: gasPaymentQuote}( + destination, + testIsmB32, + salt, + bytecode, + initCode + ); + + // assert + uint256 balanceAfter = address(sender).balance; + assertContractDeployedAndInit(sender, salt, type(SomeContract).creationCode, address(testIsm)); + assertIgpPayment(balanceBefore, balanceAfter, igp.getDefaultGasUsage()); + } + + function testFuzz_deployContract_paramISM_customMetadata_forIgp(address sender, bytes32 salt, uint64 gasLimit, uint64 overpayment) public enrollRouters { + assumeSender(sender); + + // arrange + uint256 payment = gasLimit * igp.gasPrice() + overpayment; + vm.deal(sender, payment); + + bytes memory metadata = StandardHookMetadata.formatMetadata( + 0, + gasLimit, + sender, + "" + ); + + uint256 balanceBefore = address(sender).balance; + + // act + bytes memory bytecode = type(SomeContract).creationCode; + vm.prank(sender); + originRouter.deployContract{value: payment}( + destination, + testIsmB32, + salt, + bytecode, + metadata + ); + + // assert + uint256 balanceAfter = address(sender).balance; + assertContractDeployed(sender, salt, type(SomeContract).creationCode, address(testIsm)); + assertIgpPayment(balanceBefore, balanceAfter, gasLimit); + } + + function testFuzz_deployContractAndInit_paramISM_customMetadata_forIgp(address sender, bytes32 salt, uint64 gasLimit, uint64 overpayment) public enrollRouters { + assumeSender(sender); + + // arrange + uint256 payment = gasLimit * igp.gasPrice() + overpayment; + vm.deal(sender, payment); + + bytes memory metadata = StandardHookMetadata.formatMetadata( + 0, + gasLimit, + sender, + "" + ); + + uint256 balanceBefore = address(sender).balance; + + // act + bytes memory bytecode = type(SomeContract).creationCode; + bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); + + vm.prank(sender); + originRouter.deployContractAndInit{value: payment}( + destination, + testIsmB32, + salt, + bytecode, + initCode, + metadata + ); + + // assert + uint256 balanceAfter = address(sender).balance; + assertContractDeployedAndInit(sender, salt, type(SomeContract).creationCode, address(testIsm)); + assertIgpPayment(balanceBefore, balanceAfter, gasLimit); + } + + function testFuzz_deployContract_WithFailingIsm(address sender, bytes32 salt) public enrollRouters { + assumeSender(sender); + + // arrange + string memory failureMessage = "failing ism"; + bytes32 failingIsm = TypeCasts.addressToBytes32( + address(new FailingIsm(failureMessage)) + ); + + // arrange + vm.deal(sender, gasPaymentQuote); + + // act + bytes memory bytecode = type(SomeContract).creationCode; + vm.prank(sender); + originRouter.deployContract{value: gasPaymentQuote}( + destination, + failingIsm, + salt, + bytecode + ); + + // assert + vm.expectRevert(bytes(failureMessage)); + environment.processNextPendingMessage(); + } + + function testFuzz_deployContractAndInit_WithFailingIsm(address sender, bytes32 salt) public enrollRouters { + assumeSender(sender); + + // arrange + string memory failureMessage = "failing ism"; + bytes32 failingIsm = TypeCasts.addressToBytes32( + address(new FailingIsm(failureMessage)) + ); + + // arrange + vm.deal(sender, gasPaymentQuote); + + // act + bytes memory bytecode = type(SomeContract).creationCode; + bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); + + vm.prank(sender); + originRouter.deployContractAndInit{value: gasPaymentQuote}( + destination, + failingIsm, + salt, + bytecode, + initCode + ); + + // assert + vm.expectRevert(bytes(failureMessage)); + environment.processNextPendingMessage(); + } + +} From 7d17308f085c118ebd9ca30be734f30fb2158813 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Wed, 4 Sep 2024 14:49:02 -0300 Subject: [PATCH 05/21] Remove yarn.lock from .gitignore --- .gitignore | 1 - yarn.lock | 1918 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1918 insertions(+), 1 deletion(-) create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore index e108b40..d2579c2 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ out lcov.info package-lock.json pnpm-lock.yaml -yarn.lock # broadcasts !broadcast diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..407b589 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1918 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@arbitrum/nitro-contracts@^1.2.1": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@arbitrum/nitro-contracts/-/nitro-contracts-1.3.0.tgz#75c78e074a18dc95fc5bcf5dd270896b59df4918" + integrity sha512-nNNOgqqyiOxFiF1k53u0upC6tRWar1aj2arRZoE8C99/0eMnWk9az6rUO1yhxgMyMmk5fx9Pg42oSsZ9H7noOg== + dependencies: + "@offchainlabs/upgrade-executor" "1.1.0-beta.0" + "@openzeppelin/contracts" "4.5.0" + "@openzeppelin/contracts-upgradeable" "4.5.2" + patch-package "^6.4.7" + +"@babel/code-frame@^7.0.0": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" + integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== + dependencies: + "@babel/highlight" "^7.24.7" + picocolors "^1.0.0" + +"@babel/helper-validator-identifier@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" + integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== + +"@babel/highlight@^7.24.7": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" + integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== + dependencies: + "@babel/helper-validator-identifier" "^7.24.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/runtime@^7.25.0": + version "7.25.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.6.tgz#9afc3289f7184d8d7f98b099884c26317b9264d2" + integrity sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ== + dependencies: + regenerator-runtime "^0.14.0" + +"@cosmjs/encoding@^0.32.4": + version "0.32.4" + resolved "https://registry.yarnpkg.com/@cosmjs/encoding/-/encoding-0.32.4.tgz#646e0e809f7f4f1414d8fa991fb0ffe6c633aede" + integrity sha512-tjvaEy6ZGxJchiizzTn7HVRiyTg1i4CObRRaTRPknm5EalE13SV+TCHq38gIDfyUeden4fCuaBVEdBR5+ti7Hw== + dependencies: + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" + +"@eth-optimism/contracts@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eth-optimism/contracts/-/contracts-0.6.0.tgz#15ae76222a9b4d958a550cafb1960923af613a31" + integrity sha512-vQ04wfG9kMf1Fwy3FEMqH2QZbgS0gldKhcBeBUPfO8zu68L61VI97UDXmsMQXzTsEAxK8HnokW3/gosl4/NW3w== + dependencies: + "@eth-optimism/core-utils" "0.12.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + +"@eth-optimism/core-utils@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.12.0.tgz#6337e4599a34de23f8eceb20378de2a2de82b0ea" + integrity sha512-qW+7LZYCz7i8dRa7SRlUKIo1VBU8lvN0HeXCxJR+z+xtMzMQpPds20XJNCMclszxYQHkXY00fOT6GvFw9ZL6nw== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/contracts" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/providers" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bufio "^1.0.7" + chai "^4.3.4" + +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0", "@ethersproject/contracts@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.7.0": + version "5.7.2" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@hyperlane-xyz/core@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hyperlane-xyz/core/-/core-5.1.0.tgz#4d764a7e26908e5190ef58291edba5cc38d74952" + integrity sha512-+czW35MrRKv6rFrPrnZ0t/xbu+GMR4ndJPENSeE85D8/tIoZIIMVvaLwcsiDhXJ5IQsWcAhlEEBFZi6N6+nVQw== + dependencies: + "@arbitrum/nitro-contracts" "^1.2.1" + "@eth-optimism/contracts" "^0.6.0" + "@hyperlane-xyz/utils" "5.1.0" + "@layerzerolabs/lz-evm-oapp-v2" "2.0.2" + "@openzeppelin/contracts" "^4.9.3" + "@openzeppelin/contracts-upgradeable" "^v4.9.3" + fx-portal "^1.0.3" + +"@hyperlane-xyz/utils@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hyperlane-xyz/utils/-/utils-5.1.0.tgz#5121162d90dd815af8a4762bbcb8d4995b9af93d" + integrity sha512-Gyy2IDjtgJ/MhmUwLWwC58AGa0awwKCdCfmPSqucwT/ZW+Tcu116igzukyvxGtVk4/gWh+DEivDnB/w+92clyA== + dependencies: + "@cosmjs/encoding" "^0.32.4" + "@solana/web3.js" "^1.78.0" + bignumber.js "^9.1.1" + ethers "^5.7.2" + lodash-es "^4.17.21" + pino "^8.19.0" + yaml "^2.4.1" + +"@layerzerolabs/lz-evm-messagelib-v2@^2.0.2": + version "2.3.40" + resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-evm-messagelib-v2/-/lz-evm-messagelib-v2-2.3.40.tgz#7e03070160306ac8234a7204bfd8b32f694f650e" + integrity sha512-y+35ThEMeJYg2IMCSO0qWJ9y7mnwcxkUPVv3ROb5AtHJqyeP45G267ASULVpC0tWQ9fpZRn6SKKuesL++WbuZA== + +"@layerzerolabs/lz-evm-oapp-v2@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-evm-oapp-v2/-/lz-evm-oapp-v2-2.0.2.tgz#89030de4dea0827a298fce60df65ecbc3544db0e" + integrity sha512-50hG8BKa1ywobIt2UVjI3ePQO9XBy6uT9YCN9i5IBfX6WrSZevPyDtL8OayzKtRQgkKTvprC82bdGzAoqh2RUw== + dependencies: + "@layerzerolabs/lz-evm-messagelib-v2" "^2.0.2" + "@layerzerolabs/lz-evm-protocol-v2" "^2.0.2" + "@layerzerolabs/lz-evm-v1-0.7" "^2.0.2" + +"@layerzerolabs/lz-evm-protocol-v2@^2.0.2": + version "2.3.40" + resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-evm-protocol-v2/-/lz-evm-protocol-v2-2.3.40.tgz#fc133376060599cdb65ee70879a8b801f226997e" + integrity sha512-3Beku+VLRxb+KO4fMcC7WVENLdFtdin/X7cVgwM6xzPd35C5z/EUnbBPlW0Hci788paK+MTTyluAXsWsbMDS2g== + +"@layerzerolabs/lz-evm-v1-0.7@^2.0.2": + version "2.3.40" + resolved "https://registry.yarnpkg.com/@layerzerolabs/lz-evm-v1-0.7/-/lz-evm-v1-0.7-2.3.40.tgz#8097560124439a4a5301f13f975f5df7e33a6dd7" + integrity sha512-0tTD84gmrsPmy2EGyIq1ZIm3xxzHt7eul27MYIn1D2V1APJ6qo+GlXTi4jZwy241wKpd9khNe+ATHOIoaZdlTQ== + +"@noble/curves@^1.4.2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.5.0.tgz#7a9b9b507065d516e6dce275a1e31db8d2a100dd" + integrity sha512-J5EKamIHnKPyClwVrzmaf5wSdQXgdHcPZIZLu3bwnbeCx8/7NPK5q2ZBWF+5FvYGByjiQQsJYX6jfgB2wDPn3A== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/hashes@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@noble/hashes@^1.4.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0" + integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== + +"@offchainlabs/upgrade-executor@1.1.0-beta.0": + version "1.1.0-beta.0" + resolved "https://registry.yarnpkg.com/@offchainlabs/upgrade-executor/-/upgrade-executor-1.1.0-beta.0.tgz#c4b1375176546a18aaef01a43956abfb58250e0a" + integrity sha512-mpn6PHjH/KDDjNX0pXHEKdyv8m6DVGQiI2nGzQn0JbM1nOSHJpWx6fvfjtH7YxHJ6zBZTcsKkqGkFKDtCfoSLw== + dependencies: + "@openzeppelin/contracts" "4.7.3" + "@openzeppelin/contracts-upgradeable" "4.7.3" + +"@openzeppelin/contracts-upgradeable@4.5.2": + version "4.5.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.5.2.tgz#90d9e47bacfd8693bfad0ac8a394645575528d05" + integrity sha512-xgWZYaPlrEOQo3cBj97Ufiuv79SPd8Brh4GcFYhPgb6WvAq4ppz8dWKL6h+jLAK01rUqMRp/TS9AdXgAeNvCLA== + +"@openzeppelin/contracts-upgradeable@4.7.3": + version "4.7.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.7.3.tgz#f1d606e2827d409053f3e908ba4eb8adb1dd6995" + integrity sha512-+wuegAMaLcZnLCJIvrVUDzA9z/Wp93f0Dla/4jJvIhijRrPabjQbZe6fWiECLaJyfn5ci9fqf9vTw3xpQOad2A== + +"@openzeppelin/contracts-upgradeable@^v4.9.3": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.6.tgz#38b21708a719da647de4bb0e4802ee235a0d24df" + integrity sha512-m4iHazOsOCv1DgM7eD7GupTJ+NFVujRZt1wzddDPSVGpWdKq1SKkla5htKG7+IS4d2XOCtzkUNwRZ7Vq5aEUMA== + +"@openzeppelin/contracts@4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.5.0.tgz#3fd75d57de172b3743cdfc1206883f56430409cc" + integrity sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA== + +"@openzeppelin/contracts@4.7.3": + version "4.7.3" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.7.3.tgz#939534757a81f8d69cc854c7692805684ff3111e" + integrity sha512-dGRS0agJzu8ybo44pCIf3xBaPQN/65AIXNgK8+4gzKd5kbvlqyxryUYVLJv7fK98Seyd2hDZzVEHSWAh0Bt1Yw== + +"@openzeppelin/contracts@^4.2.0", "@openzeppelin/contracts@^4.9.3": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.6.tgz#2a880a24eb19b4f8b25adc2a5095f2aa27f39677" + integrity sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA== + +"@solana/buffer-layout@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" + integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== + dependencies: + buffer "~6.0.3" + +"@solana/web3.js@^1.78.0": + version "1.95.3" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.95.3.tgz#70b5f4d76823f56b5af6403da51125fffeb65ff3" + integrity sha512-O6rPUN0w2fkNqx/Z3QJMB9L225Ex10PRDH8bTaIUPZXMPV0QP8ZpPvjQnXK+upUczlRgzHzd6SjKIha1p+I6og== + dependencies: + "@babel/runtime" "^7.25.0" + "@noble/curves" "^1.4.2" + "@noble/hashes" "^1.4.0" + "@solana/buffer-layout" "^4.0.1" + agentkeepalive "^4.5.0" + bigint-buffer "^1.1.5" + bn.js "^5.2.1" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.1" + node-fetch "^2.7.0" + rpc-websockets "^9.0.2" + superstruct "^2.0.2" + +"@solidity-parser/parser@^0.16.0": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.16.2.tgz#42cb1e3d88b3e8029b0c9befff00b634cd92d2fa" + integrity sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg== + dependencies: + antlr4ts "^0.5.0-alpha.4" + +"@swc/helpers@^0.5.11": + version "0.5.12" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.12.tgz#37aaca95284019eb5d2207101249435659709f4b" + integrity sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g== + dependencies: + tslib "^2.4.0" + +"@types/connect@^3.4.33": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/node@*": + version "22.5.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.5.2.tgz#e42344429702e69e28c839a7e16a8262a8086793" + integrity sha512-acJsPTEqYqulZS/Yp/S3GgeE6GZ0qYODUR8aVr/DkhHQ8l9nd4j5x1/ZJy9/gHrRlFMqkO6i0I3E27Alu4jjPg== + dependencies: + undici-types "~6.19.2" + +"@types/node@^12.12.54": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/uuid@^8.3.4": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== + +"@types/ws@^7.4.4": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +"@types/ws@^8.2.2": + version "8.5.12" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.12.tgz#619475fe98f35ccca2a2f6c137702d85ec247b7e" + integrity sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ== + dependencies: + "@types/node" "*" + +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + +JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + +agentkeepalive@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + +ajv@^6.12.6: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +antlr4@^4.11.0: + version "4.13.2" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.13.2.tgz#0d084ad0e32620482a9c3a0e2470c02e72e4006d" + integrity sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg== + +antlr4ts@^0.5.0-alpha.4: + version "0.5.0-alpha.4" + resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" + integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +ast-parents@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" + integrity sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-x@^3.0.2: + version "3.0.10" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.10.tgz#62de58653f8762b5d6f8d9fe30fa75f7b2585a75" + integrity sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.0, base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bech32@1.1.4, bech32@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +bigint-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" + integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== + dependencies: + bindings "^1.3.0" + +bignumber.js@^9.1.1: + version "9.1.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +borsh@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== + dependencies: + bn.js "^5.2.0" + bs58 "^4.0.0" + text-encoding-utf-8 "^1.0.2" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +bs58@^4.0.0, bs58@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +bufferutil@^4.0.1: + version "4.0.8" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.8.tgz#1de6a71092d65d7766c4d8a522b261a6e787e8ea" + integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw== + dependencies: + node-gyp-build "^4.3.0" + +bufio@^1.0.7: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.2.1.tgz#8d4ab3ddfcd5faa90f996f922f9397d41cbaf2de" + integrity sha512-9oR3zNdupcg/Ge2sSHQF3GX+kmvL/fTPvD0nd5AGLq8SjUYnTz+SlFjK/GXidndbZtIj+pVKXiWeR9w6e9wKCA== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chai@^4.3.4: + version "4.5.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.1.0" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cosmiconfig@^8.0.0: + version "8.3.6" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== + dependencies: + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +deep-eql@^4.1.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" + integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== + dependencies: + type-detect "^4.0.0" + +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +ethers@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + +events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-redact@^3.1.1: + version "3.5.0" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4" + integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A== + +fast-stable-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== + +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + +"forge-std@github:foundry-rs/forge-std#v1.8.1": + version "1.7.6" + resolved "https://codeload.github.com/foundry-rs/forge-std/tar.gz/bb4ceea94d6f10eeb5b41dc2391c6c8bf8e734ef" + +fs-extra@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fx-portal@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fx-portal/-/fx-portal-1.0.3.tgz#6882497b1eb1a148716dbd762daf5b7ab511741b" + integrity sha512-wjjc/RQzHpjimeNVrOuLLwGBcjSzj0pTTaL26wAwTTrmaeeLrs2bcM4OldA0awZcaLqQXe3oQME8oC281jxzGw== + dependencies: + "@openzeppelin/contracts" "^4.2.0" + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^8.0.3: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-wsl@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isomorphic-ws@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" + integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== + +jayson@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.2.tgz#443c26a8658703e0b2e881117b09395d88b6982e" + integrity sha512-5nzMWDHy6f+koZOuYsArh2AXs73NfWYVlFyJJuCedr93GpY+Ku8qq10ropSXVfHK+H0T6paA88ww+/dV+1fBNA== + dependencies: + "@types/connect" "^3.4.33" + "@types/node" "^12.12.54" + "@types/ws" "^7.4.4" + JSONStream "^1.3.5" + commander "^2.20.3" + delay "^5.0.0" + es6-promisify "^5.0.0" + eyes "^0.1.8" + isomorphic-ws "^4.0.1" + json-stringify-safe "^5.0.1" + uuid "^8.3.2" + ws "^7.5.10" + +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +micromatch@^4.0.2: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +ms@^2.0.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.3.0: + version "4.8.2" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.2.tgz#4f802b71c1ab2ca16af830e6c1ea7dd1ad9496fa" + integrity sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw== + +on-exit-leak-free@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" + integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +open@^7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +patch-package@^6.4.7: + version "6.5.1" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.5.1.tgz#3e5d00c16997e6160291fee06a521c42ac99b621" + integrity sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^4.1.2" + cross-spawn "^6.0.5" + find-yarn-workspace-root "^2.0.0" + fs-extra "^9.0.0" + is-ci "^2.0.0" + klaw-sync "^6.0.0" + minimist "^1.2.6" + open "^7.4.2" + rimraf "^2.6.3" + semver "^5.6.0" + slash "^2.0.0" + tmp "^0.0.33" + yaml "^1.10.2" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picocolors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pino-abstract-transport@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz#97f9f2631931e242da531b5c66d3079c12c9d1b5" + integrity sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q== + dependencies: + readable-stream "^4.0.0" + split2 "^4.0.0" + +pino-std-serializers@^6.0.0: + version "6.2.2" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz#d9a9b5f2b9a402486a5fc4db0a737570a860aab3" + integrity sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA== + +pino@^8.19.0: + version "8.21.0" + resolved "https://registry.yarnpkg.com/pino/-/pino-8.21.0.tgz#e1207f3675a2722940d62da79a7a55a98409f00d" + integrity sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q== + dependencies: + atomic-sleep "^1.0.0" + fast-redact "^3.1.1" + on-exit-leak-free "^2.1.0" + pino-abstract-transport "^1.2.0" + pino-std-serializers "^6.0.0" + process-warning "^3.0.0" + quick-format-unescaped "^4.0.3" + real-require "^0.2.0" + safe-stable-stringify "^2.3.1" + sonic-boom "^3.7.0" + thread-stream "^2.6.0" + +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + +prettier@^2.8.3: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +prettier@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105" + integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== + +process-warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-3.0.0.tgz#96e5b88884187a1dce6f5c3166d611132058710b" + integrity sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +quick-format-unescaped@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" + integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== + +readable-stream@^4.0.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" + integrity sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g== + dependencies: + abort-controller "^3.0.0" + buffer "^6.0.3" + events "^3.3.0" + process "^0.11.10" + string_decoder "^1.3.0" + +readonly-date@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/readonly-date/-/readonly-date-1.0.0.tgz#5af785464d8c7d7c40b9d738cbde8c646f97dcd9" + integrity sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ== + +real-require@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" + integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rpc-websockets@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-9.0.2.tgz#4c1568d00b8100f997379a363478f41f8f4b242c" + integrity sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw== + dependencies: + "@swc/helpers" "^0.5.11" + "@types/uuid" "^8.3.4" + "@types/ws" "^8.2.2" + buffer "^6.0.3" + eventemitter3 "^5.0.1" + uuid "^8.3.2" + ws "^8.5.0" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" + +safe-buffer@^5.0.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-stable-stringify@^2.3.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + +scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +semver@^5.5.0, semver@^5.6.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^7.5.2: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +solhint@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.6.2.tgz#2b2acbec8fdc37b2c68206a71ba89c7f519943fe" + integrity sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ== + dependencies: + "@solidity-parser/parser" "^0.16.0" + ajv "^6.12.6" + antlr4 "^4.11.0" + ast-parents "^0.0.1" + chalk "^4.1.2" + commander "^10.0.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^7.5.2" + strip-ansi "^6.0.1" + table "^6.8.1" + text-table "^0.2.0" + optionalDependencies: + prettier "^2.8.3" + +sonic-boom@^3.7.0: + version "3.8.1" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-3.8.1.tgz#d5ba8c4e26d6176c9a1d14d549d9ff579a163422" + integrity sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg== + dependencies: + atomic-sleep "^1.0.0" + +split2@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +superstruct@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54" + integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +table@^6.8.1: + version "6.8.2" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58" + integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +text-encoding-utf-8@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" + integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +thread-stream@^2.6.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-2.7.0.tgz#d8a8e1b3fd538a6cca8ce69dbe5d3d097b601e11" + integrity sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw== + dependencies: + real-require "^0.2.0" + +"through@>=2.2.7 <3": + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +tslib@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +type-detect@^4.0.0, type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +utf-8-validate@^5.0.2: + version "5.0.10" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" + integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== + dependencies: + node-gyp-build "^4.3.0" + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@7.4.6: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +ws@^7.5.10: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== + +ws@^8.5.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + +yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yaml@^2.4.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d" + integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw== From c3d217c4e9048b374685777ef2ba0a1ee9223b0a Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Wed, 4 Sep 2024 14:51:36 -0300 Subject: [PATCH 06/21] Change some natspec --- src/InterchainCreate2FactoryRouter.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol index caefaaa..0ea8cd1 100644 --- a/src/InterchainCreate2FactoryRouter.sol +++ b/src/InterchainCreate2FactoryRouter.sol @@ -181,10 +181,10 @@ contract InterchainCreate2FactoryRouter is Router { } /** - * @notice Dispatches an InterchainAccountMessage to the remote router + * @notice Dispatches an InterchainCreate2FactoryMessage to the remote router * @param _destination The remote domain * @param _ism The address of the remote ISM - * @param _messageBody The InterchainAccountMessage body + * @param _messageBody The InterchainCreate2FactoryMessage body * @param _hookMetadata The hook metadata to override with for the hook set by the owner */ function _dispatchMessage( @@ -209,7 +209,7 @@ contract InterchainCreate2FactoryRouter is Router { } /** - * @notice Returns the salt used to deploy an interchain account + * @notice Returns the salt used to deploy the contract * @param _sender The remote sender * @param _senderSalt The salt used by the sender on the remote chain * @return The CREATE2 salt used for deploying the contract From 6228ee54981fcd3727fc2e5f2198a06fe4379f6e Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Wed, 4 Sep 2024 15:03:55 -0300 Subject: [PATCH 07/21] Lint --- src/InterchainCreate2FactoryRouter.sol | 26 +- test/Foo.t.sol | 57 ---- test/InterchainCreate2FactoryRouter.t.sol | 346 ++++++++-------------- 3 files changed, 129 insertions(+), 300 deletions(-) delete mode 100644 test/Foo.t.sol diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol index 0ea8cd1..7c1c4ae 100644 --- a/src/InterchainCreate2FactoryRouter.sol +++ b/src/InterchainCreate2FactoryRouter.sol @@ -6,12 +6,8 @@ import { InterchainCreate2FactoryMessage } from "./libs/InterchainCreate2Factory // ============ External Imports ============ import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; -import { StandardHookMetadata } from "@hyperlane-xyz/hooks/libs/StandardHookMetadata.sol"; -import { EnumerableMapExtended } from "@hyperlane-xyz/libs/EnumerableMapExtended.sol"; import { Router } from "@hyperlane-xyz/client/Router.sol"; import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol"; -import { Address } from "@openzeppelin/contracts/utils/Address.sol"; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; /* * @title A contract that allows accounts on chain A to deploy contracts on chain B. @@ -134,21 +130,14 @@ contract InterchainCreate2FactoryRouter is Router { view returns (uint256 _gasPayment) { - - return _Router_quoteDispatch( - _destination,_messageBody, _hookMetadata, address(hook) - ); + return _Router_quoteDispatch(_destination, _messageBody, _hookMetadata, address(hook)); } /** * @dev Returns the address where a contract will be stored if deployed via {deploy} or {deployAndInit} by `sender`. * Any change in the `bytecode`, `sender`, or `salt` will result in a new destination address. */ - function deployedAddress( - address _sender, - bytes32 _salt, - bytes memory _bytecode - ) external view returns (address) { + function deployedAddress(address _sender, bytes32 _salt, bytes memory _bytecode) external view returns (address) { return address( uint160( uint256( @@ -168,7 +157,7 @@ contract InterchainCreate2FactoryRouter is Router { // ============ Internal Functions ============ function _handle(uint32, bytes32, bytes calldata _message) internal override { - (bytes32 _sender, , bytes32 _salt, bytes memory _bytecode, bytes memory _initCode) = + (bytes32 _sender,, bytes32 _salt, bytes memory _bytecode, bytes memory _initCode) = InterchainCreate2FactoryMessage.decode(_message); address deployedAddress_ = _deploy(_bytecode, _getSalt(_sender, _salt)); @@ -192,20 +181,13 @@ contract InterchainCreate2FactoryRouter is Router { bytes32 _ism, bytes memory _messageBody, bytes memory _hookMetadata - ) private returns (bytes32) { emit RemoteDeployDispatched(_destination, msg.sender, _destination, _ism); - return _Router_dispatch( - _destination, - msg.value, - _messageBody, - _hookMetadata, - address(hook) - ); + return _Router_dispatch(_destination, msg.value, _messageBody, _hookMetadata, address(hook)); } /** diff --git a/test/Foo.t.sol b/test/Foo.t.sol deleted file mode 100644 index 1f2dad9..0000000 --- a/test/Foo.t.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.25 <0.9.0; - -// import { Test } from "forge-std/src/Test.sol"; -// import { console2 } from "forge-std/src/console2.sol"; - -// import { Foo } from "../src/Foo.sol"; - -// interface IERC20 { -// function balanceOf(address account) external view returns (uint256); -// } - -// /// @dev If this is your first time with Forge, read this tutorial in the Foundry Book: -// /// https://book.getfoundry.sh/forge/writing-tests -// contract FooTest is Test { -// Foo internal foo; - -// /// @dev A function invoked before each test case is run. -// function setUp() public virtual { -// // Instantiate the contract-under-test. -// foo = new Foo(); -// } - -// /// @dev Basic test. Run it with `forge test -vvv` to see the console log. -// function test_Example() external view { -// console2.log("Hello World"); -// uint256 x = 42; -// assertEq(foo.id(x), x, "value mismatch"); -// } - -// /// @dev Fuzz test that provides random values for an unsigned integer, but which rejects zero as an input. -// /// If you need more sophisticated input validation, you should use the `bound` utility instead. -// /// See https://twitter.com/PaulRBerg/status/1622558791685242880 -// function testFuzz_Example(uint256 x) external view { -// vm.assume(x != 0); // or x = bound(x, 1, 100) -// assertEq(foo.id(x), x, "value mismatch"); -// } - -// /// @dev Fork test that runs against an Ethereum Mainnet fork. For this to work, you need to set -// `API_KEY_ALCHEMY` -// /// in your environment You can get an API key for free at https://alchemy.com. -// function testFork_Example() external { -// // Silently pass this test if there is no API key. -// string memory alchemyApiKey = vm.envOr("API_KEY_ALCHEMY", string("")); -// if (bytes(alchemyApiKey).length == 0) { -// return; -// } - -// // Otherwise, run the test against the mainnet fork. -// vm.createSelectFork({ urlOrAlias: "mainnet", blockNumber: 16_428_000 }); -// address usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; -// address holder = 0x7713974908Be4BEd47172370115e8b1219F4A5f0; -// uint256 actualBalance = IERC20(usdc).balanceOf(holder); -// uint256 expectedBalance = 196_307_713.810457e6; -// assertEq(actualBalance, expectedBalance); -// } -// } diff --git a/test/InterchainCreate2FactoryRouter.t.sol b/test/InterchainCreate2FactoryRouter.t.sol index 24c3dfe..9d727b9 100644 --- a/test/InterchainCreate2FactoryRouter.t.sol +++ b/test/InterchainCreate2FactoryRouter.t.sol @@ -4,26 +4,27 @@ pragma solidity ^0.8.25; import { Test } from "forge-std/src/Test.sol"; import { console2 } from "forge-std/src/console2.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import {Address} from "@openzeppelin/contracts/utils/Address.sol"; - -import {StandardHookMetadata} from "@hyperlane-xyz/hooks/libs/StandardHookMetadata.sol"; -import {MockMailbox} from "@hyperlane-xyz/mock/MockMailbox.sol"; -import {MockHyperlaneEnvironment} from "@hyperlane-xyz/mock/MockHyperlaneEnvironment.sol"; -import {TypeCasts} from "@hyperlane-xyz/libs/TypeCasts.sol"; -import {IInterchainSecurityModule} from "@hyperlane-xyz/interfaces/IInterchainSecurityModule.sol"; -import {TestInterchainGasPaymaster} from "@hyperlane-xyz/test/TestInterchainGasPaymaster.sol"; -import {IPostDispatchHook} from "@hyperlane-xyz/interfaces/hooks/IPostDispatchHook.sol"; -import {TestIsm} from "@hyperlane-xyz/test/TestIsm.sol"; - -import {InterchainCreate2FactoryRouter} from "src/InterchainCreate2FactoryRouter.sol"; -import {InterchainCreate2FactoryIsm} from "src/InterchainCreate2FactoryIsm.sol"; +import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; + +import { StandardHookMetadata } from "@hyperlane-xyz/hooks/libs/StandardHookMetadata.sol"; +import { MockMailbox } from "@hyperlane-xyz/mock/MockMailbox.sol"; +import { MockHyperlaneEnvironment } from "@hyperlane-xyz/mock/MockHyperlaneEnvironment.sol"; +import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; +import { IInterchainSecurityModule } from "@hyperlane-xyz/interfaces/IInterchainSecurityModule.sol"; +import { TestInterchainGasPaymaster } from "@hyperlane-xyz/test/TestInterchainGasPaymaster.sol"; +import { IPostDispatchHook } from "@hyperlane-xyz/interfaces/hooks/IPostDispatchHook.sol"; +import { TestIsm } from "@hyperlane-xyz/test/TestIsm.sol"; + +import { InterchainCreate2FactoryRouter } from "src/InterchainCreate2FactoryRouter.sol"; +import { InterchainCreate2FactoryIsm } from "src/InterchainCreate2FactoryIsm.sol"; import { InterchainCreate2FactoryMessage } from "src/libs/InterchainCreate2FactoryMessage.sol"; contract SomeContract { uint256 public counter; event SomeEvent(uint256 counter); + function someFunction() external { counter++; emit SomeEvent(counter); @@ -38,10 +39,7 @@ contract FailingIsm is IInterchainSecurityModule { failureMessage = _failureMessage; } - function verify( - bytes calldata, - bytes calldata - ) external view returns (bool) { + function verify(bytes calldata, bytes calldata) external view returns (bool) { revert(failureMessage); } } @@ -68,7 +66,7 @@ contract InterchainCreate2FactoryRouterBase is Test { bytes32 internal destinationRouterB32; uint256 gasPaymentQuote; - uint256 internal constant GAS_LIMIT_OVERRIDE = 60000; + uint256 internal constant GAS_LIMIT_OVERRIDE = 60_000; address internal admin = makeAddr("admin"); address internal owner = makeAddr("owner"); @@ -79,19 +77,17 @@ contract InterchainCreate2FactoryRouterBase is Test { IPostDispatchHook _customHook, IInterchainSecurityModule _ism, address _owner - ) public returns (InterchainCreate2FactoryRouter) { - InterchainCreate2FactoryRouter implementation = new InterchainCreate2FactoryRouter( - address(_mailbox) - ); + ) + public + returns (InterchainCreate2FactoryRouter) + { + InterchainCreate2FactoryRouter implementation = new InterchainCreate2FactoryRouter(address(_mailbox)); TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(implementation), admin, abi.encodeWithSelector( - InterchainCreate2FactoryRouter.initialize.selector, - address(_customHook), - address(_ism), - _owner + InterchainCreate2FactoryRouter.initialize.selector, address(_customHook), address(_ism), _owner ) ); @@ -102,29 +98,15 @@ contract InterchainCreate2FactoryRouterBase is Test { environment = new MockHyperlaneEnvironment(origin, destination); igp = new TestInterchainGasPaymaster(); - gasPaymentQuote = igp.quoteGasPayment( - destination, - igp.getDefaultGasUsage() - ); + gasPaymentQuote = igp.quoteGasPayment(destination, igp.getDefaultGasUsage()); - ism = new InterchainCreate2FactoryIsm( - address(environment.mailboxes(destination)) - ); + ism = new InterchainCreate2FactoryIsm(address(environment.mailboxes(destination))); testIsm = new TestIsm(); - originRouter = deployProxiedRouter( - environment.mailboxes(origin), - environment.igps(destination), - ism, - owner - ); - destinationRouter = deployProxiedRouter( - environment.mailboxes(destination), - environment.igps(destination), - ism, - owner - ); + originRouter = deployProxiedRouter(environment.mailboxes(origin), environment.igps(destination), ism, owner); + destinationRouter = + deployProxiedRouter(environment.mailboxes(destination), environment.igps(destination), ism, owner); environment.mailboxes(origin).setDefaultHook(address(igp)); @@ -133,7 +115,7 @@ contract InterchainCreate2FactoryRouterBase is Test { testIsmB32 = TypeCasts.addressToBytes32(address(testIsm)); } - receive() external payable {} + receive() external payable { } } contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBase { @@ -141,26 +123,15 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas modifier enrollRouters() { vm.startPrank(owner); - originRouter.enrollRemoteRouter( - destination, - destinationRouterB32 - ); + originRouter.enrollRemoteRouter(destination, destinationRouterB32); - destinationRouter.enrollRemoteRouter( - origin, - originRouterB32 - ); + destinationRouter.enrollRemoteRouter(origin, originRouterB32); vm.stopPrank(); _; -} - + } - function testFuzz_enrollRemoteRouters( - uint8 count, - uint32 domain, - bytes32 router - ) public { + function testFuzz_enrollRemoteRouters(uint8 count, uint32 domain, bytes32 router) public { vm.assume(count > 0 && count < uint256(router) && count < domain); // arrange @@ -192,11 +163,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas function test_quoteGasPayment() public enrollRouters { // arrange bytes memory messageBody = InterchainCreate2FactoryMessage.encode( - address(1), - TypeCasts.addressToBytes32(address(0)), - "", - new bytes(0), - new bytes(0) + address(1), TypeCasts.addressToBytes32(address(0)), "", new bytes(0), new bytes(0) ); // assert @@ -206,11 +173,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas function test_quoteGasPayment_gasLimitOverride() public enrollRouters { // arrange bytes memory messageBody = InterchainCreate2FactoryMessage.encode( - address(1), - TypeCasts.addressToBytes32(address(0)), - "", - new bytes(0), - new bytes(0) + address(1), TypeCasts.addressToBytes32(address(0)), "", new bytes(0), new bytes(0) ); bytes memory hookMetadata = StandardHookMetadata.overrideGasLimit(GAS_LIMIT_OVERRIDE); @@ -238,11 +201,18 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas uint256 counterBefore = SomeContract(expectedAddress).counter(); vm.expectEmit(true, true, true, true, expectedAddress); - emit SomeEvent(counterBefore+1); + emit SomeEvent(counterBefore + 1); SomeContract(expectedAddress).someFunction(); } - function assertContractDeployedAndInit(address _sender, bytes32 _salt, bytes memory _bytecode, address _ism) private { + function assertContractDeployedAndInit( + address _sender, + bytes32 _salt, + bytes memory _bytecode, + address _ism + ) + private + { address expectedAddress = destinationRouter.deployedAddress(_sender, _salt, _bytecode); assertFalse(Address.isContract(expectedAddress)); @@ -262,21 +232,17 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas uint256 counterBefore = SomeContract(expectedAddress).counter(); vm.expectEmit(true, true, true, true, expectedAddress); - emit SomeEvent(counterBefore+1); + emit SomeEvent(counterBefore + 1); SomeContract(expectedAddress).someFunction(); } - function assertIgpPayment( - uint256 balanceBefore, - uint256 balanceAfter, - uint256 gasLimit - ) private view { + function assertIgpPayment(uint256 balanceBefore, uint256 balanceAfter, uint256 gasLimit) private view { uint256 expectedGasPayment = gasLimit * igp.gasPrice(); assertEq(balanceBefore - balanceAfter, expectedGasPayment); assertEq(address(igp).balance, expectedGasPayment); } - function assumeSender(address _sender) internal view{ + function assumeSender(address _sender) internal view { vm.assume(_sender != address(0) && _sender != admin && !Address.isContract(_sender)); assumeNotPrecompile(_sender); } @@ -291,12 +257,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); vm.expectRevert("No router enrolled for domain: 2"); - originRouter.deployContract{value: gasPaymentQuote}( - destination, - "", - salt, - bytecode - ); + originRouter.deployContract{ value: gasPaymentQuote }(destination, "", salt, bytecode); } function testFuzz_deployContract_defaultISM(address sender, bytes32 salt) public enrollRouters { @@ -310,12 +271,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{value: gasPaymentQuote}( - destination, - "", - salt, - bytecode - ); + originRouter.deployContract{ value: gasPaymentQuote }(destination, "", salt, bytecode); // assert uint256 balanceAfter = address(sender).balance; @@ -337,13 +293,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{value: gasPaymentQuote}( - destination, - "", - salt, - bytecode, - initCode - ); + originRouter.deployContractAndInit{ value: gasPaymentQuote }(destination, "", salt, bytecode, initCode); // assert uint256 balanceAfter = address(sender).balance; @@ -352,32 +302,29 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertIgpPayment(balanceBefore, balanceAfter, igp.getDefaultGasUsage()); } - function testFuzz_deployContract_defaultISM_customMetadata_forIgp(address sender, bytes32 salt, uint64 gasLimit, uint64 overpayment) public enrollRouters { + function testFuzz_deployContract_defaultISM_customMetadata_forIgp( + address sender, + bytes32 salt, + uint64 gasLimit, + uint64 overpayment + ) + public + enrollRouters + { assumeSender(sender); // arrange uint256 payment = gasLimit * igp.gasPrice() + overpayment; vm.deal(sender, payment); - bytes memory metadata = StandardHookMetadata.formatMetadata( - 0, - gasLimit, - sender, - "" - ); + bytes memory metadata = StandardHookMetadata.formatMetadata(0, gasLimit, sender, ""); uint256 balanceBefore = address(sender).balance; // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{value: payment}( - destination, - "", - salt, - bytecode, - metadata - ); + originRouter.deployContract{ value: payment }(destination, "", salt, bytecode, metadata); // assert uint256 balanceAfter = address(sender).balance; @@ -386,19 +333,22 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertIgpPayment(balanceBefore, balanceAfter, gasLimit); } - function testFuzz_deployContractAndInit_defaultISM_customMetadata_forIgp(address sender, bytes32 salt, uint64 gasLimit, uint64 overpayment) public enrollRouters { + function testFuzz_deployContractAndInit_defaultISM_customMetadata_forIgp( + address sender, + bytes32 salt, + uint64 gasLimit, + uint64 overpayment + ) + public + enrollRouters + { assumeSender(sender); // arrange uint256 payment = gasLimit * igp.gasPrice() + overpayment; vm.deal(sender, payment); - bytes memory metadata = StandardHookMetadata.formatMetadata( - 0, - gasLimit, - sender, - "" - ); + bytes memory metadata = StandardHookMetadata.formatMetadata(0, gasLimit, sender, ""); uint256 balanceBefore = address(sender).balance; @@ -407,14 +357,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{value: payment}( - destination, - "", - salt, - bytecode, - initCode, - metadata - ); + originRouter.deployContractAndInit{ value: payment }(destination, "", salt, bytecode, initCode, metadata); // assert uint256 balanceAfter = address(sender).balance; @@ -423,46 +366,46 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertIgpPayment(balanceBefore, balanceAfter, gasLimit); } - function testFuzz_deployContract_defaultISM_reverts_underpayment(address sender, bytes32 salt, uint64 gasLimit, uint64 payment) public enrollRouters { + function testFuzz_deployContract_defaultISM_reverts_underpayment( + address sender, + bytes32 salt, + uint64 gasLimit, + uint64 payment + ) + public + enrollRouters + { assumeSender(sender); vm.assume(payment < gasLimit * igp.gasPrice()); // arrange vm.deal(sender, payment); - bytes memory metadata = StandardHookMetadata.formatMetadata( - 0, - gasLimit, - sender, - "" - ); + bytes memory metadata = StandardHookMetadata.formatMetadata(0, gasLimit, sender, ""); // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); vm.expectRevert("IGP: insufficient interchain gas payment"); - originRouter.deployContract{value: payment}( - destination, - "", - salt, - bytecode, - metadata - ); + originRouter.deployContract{ value: payment }(destination, "", salt, bytecode, metadata); } - function testFuzz_deployContractAndInit_defaultISM_reverts_underpayment(address sender, bytes32 salt, uint64 gasLimit, uint64 payment) public enrollRouters { + function testFuzz_deployContractAndInit_defaultISM_reverts_underpayment( + address sender, + bytes32 salt, + uint64 gasLimit, + uint64 payment + ) + public + enrollRouters + { assumeSender(sender); vm.assume(payment < gasLimit * igp.gasPrice()); // arrange vm.deal(sender, payment); - bytes memory metadata = StandardHookMetadata.formatMetadata( - 0, - gasLimit, - sender, - "" - ); + bytes memory metadata = StandardHookMetadata.formatMetadata(0, gasLimit, sender, ""); // act bytes memory bytecode = type(SomeContract).creationCode; @@ -470,14 +413,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas vm.prank(sender); vm.expectRevert("IGP: insufficient interchain gas payment"); - originRouter.deployContractAndInit{value: payment}( - destination, - "", - salt, - bytecode, - initCode, - metadata - ); + originRouter.deployContractAndInit{ value: payment }(destination, "", salt, bytecode, initCode, metadata); } function testFuzz_deployContract_paramISM(address sender, bytes32 salt) public enrollRouters { @@ -491,12 +427,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{value: gasPaymentQuote}( - destination, - testIsmB32, - salt, - bytecode - ); + originRouter.deployContract{ value: gasPaymentQuote }(destination, testIsmB32, salt, bytecode); // assert uint256 balanceAfter = address(sender).balance; @@ -517,13 +448,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{value: gasPaymentQuote}( - destination, - testIsmB32, - salt, - bytecode, - initCode - ); + originRouter.deployContractAndInit{ value: gasPaymentQuote }(destination, testIsmB32, salt, bytecode, initCode); // assert uint256 balanceAfter = address(sender).balance; @@ -531,32 +456,29 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertIgpPayment(balanceBefore, balanceAfter, igp.getDefaultGasUsage()); } - function testFuzz_deployContract_paramISM_customMetadata_forIgp(address sender, bytes32 salt, uint64 gasLimit, uint64 overpayment) public enrollRouters { + function testFuzz_deployContract_paramISM_customMetadata_forIgp( + address sender, + bytes32 salt, + uint64 gasLimit, + uint64 overpayment + ) + public + enrollRouters + { assumeSender(sender); // arrange uint256 payment = gasLimit * igp.gasPrice() + overpayment; vm.deal(sender, payment); - bytes memory metadata = StandardHookMetadata.formatMetadata( - 0, - gasLimit, - sender, - "" - ); + bytes memory metadata = StandardHookMetadata.formatMetadata(0, gasLimit, sender, ""); uint256 balanceBefore = address(sender).balance; // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{value: payment}( - destination, - testIsmB32, - salt, - bytecode, - metadata - ); + originRouter.deployContract{ value: payment }(destination, testIsmB32, salt, bytecode, metadata); // assert uint256 balanceAfter = address(sender).balance; @@ -564,19 +486,22 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertIgpPayment(balanceBefore, balanceAfter, gasLimit); } - function testFuzz_deployContractAndInit_paramISM_customMetadata_forIgp(address sender, bytes32 salt, uint64 gasLimit, uint64 overpayment) public enrollRouters { + function testFuzz_deployContractAndInit_paramISM_customMetadata_forIgp( + address sender, + bytes32 salt, + uint64 gasLimit, + uint64 overpayment + ) + public + enrollRouters + { assumeSender(sender); // arrange uint256 payment = gasLimit * igp.gasPrice() + overpayment; vm.deal(sender, payment); - bytes memory metadata = StandardHookMetadata.formatMetadata( - 0, - gasLimit, - sender, - "" - ); + bytes memory metadata = StandardHookMetadata.formatMetadata(0, gasLimit, sender, ""); uint256 balanceBefore = address(sender).balance; @@ -585,13 +510,8 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{value: payment}( - destination, - testIsmB32, - salt, - bytecode, - initCode, - metadata + originRouter.deployContractAndInit{ value: payment }( + destination, testIsmB32, salt, bytecode, initCode, metadata ); // assert @@ -605,22 +525,15 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // arrange string memory failureMessage = "failing ism"; - bytes32 failingIsm = TypeCasts.addressToBytes32( - address(new FailingIsm(failureMessage)) - ); + bytes32 failingIsm = TypeCasts.addressToBytes32(address(new FailingIsm(failureMessage))); - // arrange + // arrange vm.deal(sender, gasPaymentQuote); // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{value: gasPaymentQuote}( - destination, - failingIsm, - salt, - bytecode - ); + originRouter.deployContract{ value: gasPaymentQuote }(destination, failingIsm, salt, bytecode); // assert vm.expectRevert(bytes(failureMessage)); @@ -632,11 +545,9 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // arrange string memory failureMessage = "failing ism"; - bytes32 failingIsm = TypeCasts.addressToBytes32( - address(new FailingIsm(failureMessage)) - ); + bytes32 failingIsm = TypeCasts.addressToBytes32(address(new FailingIsm(failureMessage))); - // arrange + // arrange vm.deal(sender, gasPaymentQuote); // act @@ -644,17 +555,10 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{value: gasPaymentQuote}( - destination, - failingIsm, - salt, - bytecode, - initCode - ); + originRouter.deployContractAndInit{ value: gasPaymentQuote }(destination, failingIsm, salt, bytecode, initCode); // assert vm.expectRevert(bytes(failureMessage)); environment.processNextPendingMessage(); } - } From a5536e6d9aa0e89d1c286f86af600c0ba049b216 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Wed, 4 Sep 2024 15:13:46 -0300 Subject: [PATCH 08/21] Update README --- README.md | 107 ++++-------------------------------------------------- 1 file changed, 8 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index 31ce46d..1c84f12 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,16 @@ -# Foundry Template [![Open in Gitpod][gitpod-badge]][gitpod] [![Github Actions][gha-badge]][gha] [![Foundry][foundry-badge]][foundry] [![License: MIT][license-badge]][license] -[gitpod]: https://gitpod.io/#https://github.com/BootNodeDev/hyperlane-create2-factory-router -[gitpod-badge]: https://img.shields.io/badge/Gitpod-Open%20in%20Gitpod-FFB45B?logo=gitpod -[gha]: https://github.com/BootNodeDev/hyperlane-create2-factory-router/actions -[gha-badge]: https://github.com/BootNodeDev/hyperlane-create2-factory-router/actions/workflows/ci.yml/badge.svg -[foundry]: https://getfoundry.sh/ -[foundry-badge]: https://img.shields.io/badge/Built%20with-Foundry-FFDB1C.svg -[license]: https://opensource.org/licenses/MIT -[license-badge]: https://img.shields.io/badge/License-MIT-blue.svg +# Hyperlane InterchainCreate2FactoryRouter -A Foundry-based template for developing Solidity smart contracts, with sensible defaults. +This repo contains a possible solution for https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/2232. -## What's Inside +The `InterchainCreate2FactoryRouter` would allow to deploy a contract on any given chain Hyperlane and the router are deployed from another chain with the same conditions. +This allows developers to just have a balance on one chain but deploy contracts on multiple chains. -- [Forge](https://github.com/foundry-rs/foundry/blob/master/forge): compile, test, fuzz, format, and deploy smart - contracts -- [Forge Std](https://github.com/foundry-rs/forge-std): collection of helpful contracts and utilities for testing -- [Prettier](https://github.com/prettier/prettier): code formatter for non-Solidity files -- [Solhint](https://github.com/protofire/solhint): linter for Solidity code +## How to use -## Getting Started - -Click the [`Use this template`](https://github.com/PaulRBerg/foundry-template/generate) button at the top of the page to -create a new repository with this repo as the initial state. - -Or, if you prefer to install the template manually: - -```sh -$ mkdir my-project -$ cd my-project -$ forge init --template PaulRBerg/foundry-template -$ bun install # install Solhint, Prettier, and other Node.js deps -``` - -If this is your first time with Foundry, check out the -[installation](https://github.com/foundry-rs/foundry#installation) instructions. - -## Features - -This template builds upon the frameworks and libraries mentioned above, so please consult their respective documentation -for details about their specific features. - -For example, if you're interested in exploring Foundry in more detail, you should look at the -[Foundry Book](https://book.getfoundry.sh/). In particular, you may be interested in reading the -[Writing Tests](https://book.getfoundry.sh/forge/writing-tests.html) tutorial. - -### Sensible Defaults - -This template comes with a set of sensible default configurations for you to use. These defaults can be found in the -following files: - -```text -├── .editorconfig -├── .gitignore -├── .prettierignore -├── .prettierrc.yml -├── .solhint.json -├── foundry.toml -└── remappings.txt -``` - -### VSCode Integration - -This template is IDE agnostic, but for the best user experience, you may want to use it in VSCode alongside Nomic -Foundation's [Solidity extension](https://marketplace.visualstudio.com/items?itemName=NomicFoundation.hardhat-solidity). - -For guidance on how to integrate a Foundry project in VSCode, please refer to this -[guide](https://book.getfoundry.sh/config/vscode). - -### GitHub Actions - -This template comes with GitHub Actions pre-configured. Your contracts will be linted and tested on every push and pull -request made to the `main` branch. - -You can edit the CI script in [.github/workflows/ci.yml](./.github/workflows/ci.yml). +TODO: + - Write instruction about how to send deployment messages. + - Write an script for sending interchain messages. ## Installing Dependencies @@ -89,14 +26,6 @@ This is how to install dependencies: Note that OpenZeppelin Contracts is pre-installed, so you can follow that as an example. -## Writing Tests - -To write a new test contract, you start by importing `Test` from `forge-std`, and then you inherit it in your test -contract. Forge Std comes with a pre-instantiated [cheatcodes](https://book.getfoundry.sh/cheatcodes/) environment -accessible via the `vm` property. If you would like to view the logs in the terminal output, you can add the `-vvv` flag -and use [console.log](https://book.getfoundry.sh/faq?highlight=console.log#how-do-i-use-consolelog). - -This template comes with an example test contract [Foo.t.sol](./test/Foo.t.sol) ## Usage @@ -180,26 +109,6 @@ Run the tests: $ forge test ``` -Generate test coverage and output result to the terminal: - -```sh -$ bun run test:coverage -``` - -Generate test coverage with lcov report (you'll have to open the `./coverage/index.html` file in your browser, to do so -simply copy paste the path): - -```sh -$ bun run test:coverage:report -``` - -## Related Efforts - -- [abigger87/femplate](https://github.com/abigger87/femplate) -- [cleanunicorn/ethereum-smartcontract-template](https://github.com/cleanunicorn/ethereum-smartcontract-template) -- [foundry-rs/forge-template](https://github.com/foundry-rs/forge-template) -- [FrankieIsLost/forge-template](https://github.com/FrankieIsLost/forge-template) - ## License This project is licensed under MIT. From e15a44cedcaea79c68168e93a0215aea6013c8ad Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Wed, 4 Sep 2024 15:16:35 -0300 Subject: [PATCH 09/21] Lint --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 1c84f12..ccc2a8f 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,17 @@ - # Hyperlane InterchainCreate2FactoryRouter This repo contains a possible solution for https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/2232. -The `InterchainCreate2FactoryRouter` would allow to deploy a contract on any given chain Hyperlane and the router are deployed from another chain with the same conditions. -This allows developers to just have a balance on one chain but deploy contracts on multiple chains. +The `InterchainCreate2FactoryRouter` would allow to deploy a contract on any given chain Hyperlane and the router are +deployed from another chain with the same conditions. This allows developers to just have a balance on one chain but +deploy contracts on multiple chains. ## How to use TODO: - - Write instruction about how to send deployment messages. - - Write an script for sending interchain messages. + +- Write instruction about how to send deployment messages. +- Write an script for sending interchain messages. ## Installing Dependencies @@ -26,7 +27,6 @@ This is how to install dependencies: Note that OpenZeppelin Contracts is pre-installed, so you can follow that as an example. - ## Usage This is a list of the most frequently needed commands. From 16dea9139401fb666d7594753d72fc3bef341086 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Mon, 9 Sep 2024 14:24:27 -0300 Subject: [PATCH 10/21] Add natspec comments to router --- src/InterchainCreate2FactoryRouter.sol | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol index 7c1c4ae..9034872 100644 --- a/src/InterchainCreate2FactoryRouter.sol +++ b/src/InterchainCreate2FactoryRouter.sol @@ -50,6 +50,13 @@ contract InterchainCreate2FactoryRouter is Router { // ============ External Functions ============ + /** + * @notice Deploys a contract on the `_destination` chain + * @param _destination The remote domain + * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM + * @param _salt The salt used for deploying the contract with CREATE2 + * @param _bytecode The bytecode of the contract to deploy + */ function deployContract( uint32 _destination, bytes32 _ism, @@ -65,6 +72,14 @@ contract InterchainCreate2FactoryRouter is Router { return _dispatchMessage(_destination, _ism, _body, ""); } + /** + * @notice Deploys a contract on the `_destination` chain with hook metadata + * @param _destination The remote domain + * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM + * @param _salt The salt used for deploying the contract with CREATE2 + * @param _bytecode The bytecode of the contract to deploy + * @param _hookMetadata The hook metadata to override with for the hook set by the owner + */ function deployContract( uint32 _destination, bytes32 _ism, @@ -81,6 +96,14 @@ contract InterchainCreate2FactoryRouter is Router { return _dispatchMessage(_destination, _ism, _body, _hookMetadata); } + /** + * @notice Deploys and initialize a contract on the `_destination` chain + * @param _destination The remote domain + * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM + * @param _salt The salt used for deploying the contract with CREATE2 + * @param _bytecode The bytecode of the contract to deploy + * @param _initCode The initialization that is called after the contract is deployed + */ function deployContractAndInit( uint32 _destination, bytes32 _ism, @@ -97,6 +120,15 @@ contract InterchainCreate2FactoryRouter is Router { return _dispatchMessage(_destination, _ism, _body, ""); } + /** + * @notice Deploys and initialize a contract on the `_destination` chain with hook metadata + * @param _destination The remote domain + * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM + * @param _salt The salt used for deploying the contract with CREATE2 + * @param _bytecode The bytecode of the contract to deploy + * @param _initCode The initialization that is called after the contract is deployed + * @param _hookMetadata The hook metadata to override with for the hook set by the owner + */ function deployContractAndInit( uint32 _destination, bytes32 _ism, @@ -156,6 +188,10 @@ contract InterchainCreate2FactoryRouter is Router { // ============ Internal Functions ============ + /** + * @notice Deploys the contract using the data from an incoming message + * @param _message The message containing the data sent by the remote router + */ function _handle(uint32, bytes32, bytes calldata _message) internal override { (bytes32 _sender,, bytes32 _salt, bytes memory _bytecode, bytes memory _initCode) = InterchainCreate2FactoryMessage.decode(_message); From 8264aa21f6a28549415041ed67e3ad6c6caa5cd3 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Mon, 9 Sep 2024 14:25:16 -0300 Subject: [PATCH 11/21] Add scripts for deploying, enrolling and example deploy --- .env.example | 32 +++++++++++------ foundry.toml | 15 ++++---- package.json | 13 +++++-- script/Base.s.sol | 41 --------------------- script/Deploy.s.sol | 13 ------- script/DeployRouter.s.sol | 54 ++++++++++++++++++++++++++++ script/EnrollRouters.s.sol | 35 ++++++++++++++++++ script/InterchainDeployExample.s.sol | 53 +++++++++++++++++++++++++++ script/utils/TestDeployContract.sol | 13 +++++++ yarn.lock | 18 ++++++++++ 10 files changed, 212 insertions(+), 75 deletions(-) delete mode 100644 script/Base.s.sol delete mode 100644 script/Deploy.s.sol create mode 100644 script/DeployRouter.s.sol create mode 100644 script/EnrollRouters.s.sol create mode 100644 script/InterchainDeployExample.s.sol create mode 100644 script/utils/TestDeployContract.sol diff --git a/.env.example b/.env.example index 98c1028..8cddc57 100644 --- a/.env.example +++ b/.env.example @@ -1,11 +1,23 @@ -export API_KEY_ALCHEMY="YOUR_API_KEY_ALCHEMY" -export API_KEY_ARBISCAN="YOUR_API_KEY_ARBISCAN" -export API_KEY_BSCSCAN="YOUR_API_KEY_BSCSCAN" -export API_KEY_ETHERSCAN="YOUR_API_KEY_ETHERSCAN" -export API_KEY_GNOSISSCAN="YOUR_API_KEY_GNOSISSCAN" -export API_KEY_INFURA="YOUR_API_KEY_INFURA" -export API_KEY_OPTIMISTIC_ETHERSCAN="YOUR_API_KEY_OPTIMISTIC_ETHERSCAN" -export API_KEY_POLYGONSCAN="YOUR_API_KEY_POLYGONSCAN" -export API_KEY_SNOWTRACE="YOUR_API_KEY_SNOWTRACE" -export MNEMONIC="YOUR_MNEMONIC" export FOUNDRY_PROFILE="default" + +export NETWORK="network where the script is run" +export API_KEY_ALCHEMY="YOUR_API_KEY_ALCHEMY" +export ETHERSCAN_API_KEY="your etherscar or whateverscarn api key" + +# DeployRouter +export NETWORK="network to deploy" +export DEPLOYER_PK="your deployer private key" +export ISM_SALT="salt for deploying ISM" +export MAILBOX="local mailbox address" +export PROXY_ADMIN="address of the proxy admin" +export ROUTER_OWNER="address of the router owner" +export ROUTER_IMPLEMENTATION="optional address of the router implementation, if not provided it will be deployed" +export ISM="optional address of the ISM, if not provided it will be deployed" +export CUSTOM_HOOK="optional address of the ISM, if not provided ZERO ADDRESS is used and messages will use the mailbox default hook" + +# EnrollRouters + +export ROUTER_OWNER_PK="router owner private key" +export ROUTERS="addresses of the routers to enroll, separated by commas" +export DOMAINS="domains of the routers to enroll, separated by commas" +export ROUTER="address of the local router" diff --git a/foundry.toml b/foundry.toml index dacd6da..c4901f0 100644 --- a/foundry.toml +++ b/foundry.toml @@ -25,7 +25,6 @@ base = { key = "${API_KEY_BASESCAN}" } bnb_smart_chain = { key = "${API_KEY_BSCSCAN}" } gnosis_chain = { key = "${API_KEY_GNOSISSCAN}" } - goerli = { key = "${API_KEY_ETHERSCAN}" } mainnet = { key = "${API_KEY_ETHERSCAN}" } optimism = { key = "${API_KEY_OPTIMISTIC_ETHERSCAN}" } polygon = { key = "${API_KEY_POLYGONSCAN}" } @@ -42,14 +41,14 @@ wrap_comments = true [rpc_endpoints] - arbitrum = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}" - avalanche = "https://avalanche-mainnet.infura.io/v3/${API_KEY_INFURA}" + mainnet = "https://eth-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}" + arbitrum = "https://arbitrum-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}" + avalanche = "https://avalanche-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}" base = "https://mainnet.base.org" bnb_smart_chain = "https://bsc-dataseed.binance.org" gnosis_chain = "https://rpc.gnosischain.com" - goerli = "https://goerli.infura.io/v3/${API_KEY_INFURA}" localhost = "http://localhost:8545" - mainnet = "https://eth-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}" - optimism = "https://optimism-mainnet.infura.io/v3/${API_KEY_INFURA}" - polygon = "https://polygon-mainnet.infura.io/v3/${API_KEY_INFURA}" - sepolia = "https://sepolia.infura.io/v3/${API_KEY_INFURA}" + optimism = "https://optimism-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}" + polygon = "https://polygon-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}" + optimism-sepolia = "https://opt-sepolia.g.alchemy.com/v2/${API_KEY_ALCHEMY}" + sepolia = "https://eth-sepolia.g.alchemy.com/v2/${API_KEY_ALCHEMY}" diff --git a/package.json b/package.json index 04ce1f8..7ed5b36 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "dependencies": { "@hyperlane-xyz/core": "^5.1.0", "@openzeppelin/contracts": "^4.9.3", - "@openzeppelin/contracts-upgradeable": "^v4.9.3" + "@openzeppelin/contracts-upgradeable": "^v4.9.3", + "dotenv-run-script": "^0.4.1" }, "devDependencies": { "forge-std": "github:foundry-rs/forge-std#v1.8.1", @@ -27,7 +28,7 @@ ], "private": true, "scripts": { - "clean": "rm -rf cache out", + "clean": "rm -rf cache out && forge clean", "build": "forge build", "lint": "yarn run lint:sol && yarn run prettier:check", "lint:sol": "forge fmt --check && yarn solhint '{script,src,test}/**/*.sol'", @@ -36,6 +37,12 @@ "prettier:write": "prettier --write \"**/*.{json,md,yml}\" --ignore-path \".prettierignore\"", "test": "forge test -vvv", "test:coverage": "forge coverage", - "test:coverage:report": "forge coverage --report lcov && genhtml lcov.info --branch-coverage --output-dir coverage" + "test:coverage:report": "forge coverage --report lcov && genhtml lcov.info --branch-coverage --output-dir coverage", + "deployRouter": "forge script script/DeployRouter.s.sol:DeployRouter -f $NETWORK --broadcast --verify --etherscan-api-key $ETHERSCAN_API_KEY --chain $NETWORK --slow -vvvv", + "run:deployRouter": "dotenv-run-script deployRouter", + "enrollRouters": "forge script script/EnrollRouters.s.sol:EnrollRouters -f $NETWORK --broadcast --slow -vvvv", + "run:enrollRouters": "dotenv-run-script enrollRouters", + "interchainDeploy": "forge script script/InterchainDeployExample.s.sol:InterchainDeployExample -f $NETWORK --broadcast --slow -vvvv", + "run:interchainDeploy": "dotenv-run-script interchainDeploy" } } diff --git a/script/Base.s.sol b/script/Base.s.sol deleted file mode 100644 index 07135a2..0000000 --- a/script/Base.s.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.8.25 <0.9.0; - -import { Script } from "forge-std/src/Script.sol"; - -abstract contract BaseScript is Script { - /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. - string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; - - /// @dev Needed for the deterministic deployments. - bytes32 internal constant ZERO_SALT = bytes32(0); - - /// @dev The address of the transaction broadcaster. - address internal broadcaster; - - /// @dev Used to derive the broadcaster's address if $ETH_FROM is not defined. - string internal mnemonic; - - /// @dev Initializes the transaction broadcaster like this: - /// - /// - If $ETH_FROM is defined, use it. - /// - Otherwise, derive the broadcaster address from $MNEMONIC. - /// - If $MNEMONIC is not defined, default to a test mnemonic. - /// - /// The use case for $ETH_FROM is to specify the broadcaster key and its address via the command line. - constructor() { - address from = vm.envOr({ name: "ETH_FROM", defaultValue: address(0) }); - if (from != address(0)) { - broadcaster = from; - } else { - mnemonic = vm.envOr({ name: "MNEMONIC", defaultValue: TEST_MNEMONIC }); - (broadcaster,) = deriveRememberKey({ mnemonic: mnemonic, index: 0 }); - } - } - - modifier broadcast() { - vm.startBroadcast(broadcaster); - _; - vm.stopBroadcast(); - } -} diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol deleted file mode 100644 index 7da5749..0000000 --- a/script/Deploy.s.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.25 <0.9.0; - -// import { Foo } from "../src/Foo.sol"; - -import { BaseScript } from "./Base.s.sol"; - -/// @dev See the Solidity Scripting tutorial: https://book.getfoundry.sh/tutorials/solidity-scripting -contract Deploy is BaseScript { -// function run() public broadcast returns (Foo foo) { -// foo = new Foo(); -// } -} diff --git a/script/DeployRouter.s.sol b/script/DeployRouter.s.sol new file mode 100644 index 0000000..a2c512e --- /dev/null +++ b/script/DeployRouter.s.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.25 <0.9.0; + +import { Script } from "forge-std/src/Script.sol"; +import { console2 } from "forge-std/src/console2.sol"; + +import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +import { InterchainCreate2FactoryRouter } from "../src/InterchainCreate2FactoryRouter.sol"; +import { InterchainCreate2FactoryIsm } from "../src/InterchainCreate2FactoryIsm.sol"; + +/// @dev See the Solidity Scripting tutorial: https://book.getfoundry.sh/tutorials/solidity-scripting +contract DeployRouter is Script { + function run() public { + + uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PK"); + + string memory ISM_SALT = vm.envString("ISM_SALT"); + address mailbox = vm.envAddress("MAILBOX"); + address admin = vm.envAddress("PROXY_ADMIN"); + address owner = vm.envAddress("ROUTER_OWNER"); + address routerImpl = vm.envOr("ROUTER_IMPLEMENTATION", address(0)); + address ism = vm.envOr("ISM", address(0)); + address customHook = vm.envOr("CUSTOM_HOOK", address(0)); + + bytes32 ismSalt = keccak256(abi.encodePacked(ISM_SALT, vm.addr(deployerPrivateKey))); + + vm.startBroadcast(deployerPrivateKey); + + if (ism == address(0)) { + ism = address(new InterchainCreate2FactoryIsm{salt: ismSalt}(mailbox)); + } + + if (routerImpl == address(0)) { + routerImpl = address(new InterchainCreate2FactoryRouter(mailbox)); + } + + TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( + address(routerImpl), + admin, + abi.encodeWithSelector( + InterchainCreate2FactoryRouter.initialize.selector, customHook, ism, owner + ) + ); + + vm.stopBroadcast(); + + // solhint-disable-next-line no-console + console2.log('Proxy:', address(proxy)); + console2.log('Implementation:', routerImpl); + console2.log('ISM:', ism); + + } +} diff --git a/script/EnrollRouters.s.sol b/script/EnrollRouters.s.sol new file mode 100644 index 0000000..621436f --- /dev/null +++ b/script/EnrollRouters.s.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.25 <0.9.0; + +import { Script } from "forge-std/src/Script.sol"; +import { console2 } from "forge-std/src/console2.sol"; + +import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; +import { InterchainCreate2FactoryRouter } from "src/InterchainCreate2FactoryRouter.sol"; + +/// @dev See the Solidity Scripting tutorial: https://book.getfoundry.sh/tutorials/solidity-scripting +contract EnrollRouters is Script { + function run() public { + uint256 ownerPrivateKey = vm.envUint("ROUTER_OWNER_PK"); + + address[] memory routers = vm.envAddress("ROUTERS", ","); + uint256[] memory domains = vm.envUint("DOMAINS", ","); + + address localRouter = vm.envAddress("ROUTER"); + + if (routers.length != domains.length) { + revert('Invalid input'); + } + + vm.startBroadcast(ownerPrivateKey); + + for (uint i = 0; i < routers.length; i++) { + InterchainCreate2FactoryRouter(localRouter).enrollRemoteRouter( + uint32(domains[i]), + TypeCasts.addressToBytes32(routers[i]) + ); + } + + vm.stopBroadcast(); + } +} diff --git a/script/InterchainDeployExample.s.sol b/script/InterchainDeployExample.s.sol new file mode 100644 index 0000000..6efb421 --- /dev/null +++ b/script/InterchainDeployExample.s.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.25 <0.9.0; + +import { Script } from "forge-std/src/Script.sol"; +import { console2 } from "forge-std/src/console2.sol"; + +import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; +import { InterchainCreate2FactoryRouter } from "src/InterchainCreate2FactoryRouter.sol"; +import { InterchainCreate2FactoryMessage } from "src/libs/InterchainCreate2FactoryMessage.sol"; +import { TestDeployContract} from "./utils/TestDeployContract.sol"; + +/// @dev See the Solidity Scripting tutorial: https://book.getfoundry.sh/tutorials/solidity-scripting +contract InterchainDeployExample is Script { + function run() public { + uint256 ownerPrivateKey = vm.envUint("ROUTER_OWNER_PK"); + address localRouter = vm.envAddress("ROUTER"); + + bytes memory bytecode = type(TestDeployContract).creationCode; + bytes32 salt = "testDeployContract.0.0.2"; + bytes32 ism = TypeCasts.addressToBytes32(address(0)); + uint32 destination = uint32(11155111); + + bytes memory messageBody = InterchainCreate2FactoryMessage.encode( + vm.addr(ownerPrivateKey), + ism, + salt, + bytecode, + new bytes(0) + ); + + vm.startBroadcast(ownerPrivateKey); + + uint256 gasPayment = InterchainCreate2FactoryRouter(localRouter).quoteGasPayment( + destination, + messageBody, + new bytes(0) + ); + + bytes32 messageId = InterchainCreate2FactoryRouter(localRouter).deployContractAndInit{value: gasPayment}( + destination, + ism, + salt, + bytecode, + abi.encodeWithSelector(TestDeployContract.increment.selector) + ); + + vm.stopBroadcast(); + + console2.log('Gas Payment:', gasPayment); + console2.log('messageId:'); + console2.logBytes32(messageId); + } +} diff --git a/script/utils/TestDeployContract.sol b/script/utils/TestDeployContract.sol new file mode 100644 index 0000000..99498bb --- /dev/null +++ b/script/utils/TestDeployContract.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.25 <0.9.0; + +contract TestDeployContract { + uint256 public counter; + + event Incremented(uint256 value); + + function increment() public { + counter++; + emit Incremented(counter); + } +} diff --git a/yarn.lock b/yarn.lock index 407b589..62ff196 100644 --- a/yarn.lock +++ b/yarn.lock @@ -953,6 +953,24 @@ delay@^5.0.0: resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== +dotenv-expand@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" + integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== + +dotenv-run-script@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/dotenv-run-script/-/dotenv-run-script-0.4.1.tgz#918161e4344cd39e27996d71a155d1f3a06470d6" + integrity sha512-5mHhOVcSMY7X9lC50xjJL2oKiW75gqvpZpUmJRrFMOAdbNZ+hk8z1wIG9Rh/noEzbgRqYd34EmOpbStc1d+GOg== + dependencies: + dotenv "^16.3.1" + dotenv-expand "^10.0.0" + +dotenv@^16.3.1: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== + elliptic@6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" From d4ba0b3d5022d21d1cd660356461e1312a8c11ab Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Mon, 9 Sep 2024 15:50:08 -0300 Subject: [PATCH 12/21] Improve README --- .env.example | 8 ++++--- README.md | 34 ++++++++++++++++++++++++---- script/InterchainDeployExample.s.sol | 4 ++-- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/.env.example b/.env.example index 8cddc57..a44751b 100644 --- a/.env.example +++ b/.env.example @@ -2,10 +2,9 @@ export FOUNDRY_PROFILE="default" export NETWORK="network where the script is run" export API_KEY_ALCHEMY="YOUR_API_KEY_ALCHEMY" -export ETHERSCAN_API_KEY="your etherscar or whateverscarn api key" # DeployRouter -export NETWORK="network to deploy" +export ETHERSCAN_API_KEY="your etherscar or whateverscarn api key" export DEPLOYER_PK="your deployer private key" export ISM_SALT="salt for deploying ISM" export MAILBOX="local mailbox address" @@ -16,8 +15,11 @@ export ISM="optional address of the ISM, if not provided it will be deployed" export CUSTOM_HOOK="optional address of the ISM, if not provided ZERO ADDRESS is used and messages will use the mailbox default hook" # EnrollRouters - export ROUTER_OWNER_PK="router owner private key" export ROUTERS="addresses of the routers to enroll, separated by commas" export DOMAINS="domains of the routers to enroll, separated by commas" export ROUTER="address of the local router" + +# Deploy Example +export DESTINATION="network id where the example contract will be deployed" +export EXAMPLE_SALT="a salt for deployng the example contract on destination network" diff --git a/README.md b/README.md index ccc2a8f..62114d1 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,38 @@ The `InterchainCreate2FactoryRouter` would allow to deploy a contract on any giv deployed from another chain with the same conditions. This allows developers to just have a balance on one chain but deploy contracts on multiple chains. -## How to use +## Deploy the router -TODO: +- Run `yarn install` to install all the dependencies +- Create a `.env` file base on the [.env.example file](./.env.example) file, and set the required variables depending + which script you are going to run. -- Write instruction about how to send deployment messages. -- Write an script for sending interchain messages. +Set the following environment variables required for running all the scripts, on each network. + +- `NETWORK`: the name of the network you want to run the script +- `API_KEY_ALCHEMY`: you Alchemy API key + +If the network is not listed under the `rpc_endpoints` section of the [foundry.toml file](./foundry.toml) you'll have to add a new entry for it. + +For deploying the router you have to run the `yarn run:deployRouter`. Make sure the following environment variable are set: +- `DEPLOYER_PK`: deployer private key +- `MAILBOX`: address of Hyperlane Mailbox contract on the chain +- `ROUTER_OWNER`: address of the router owner +- `PROXY_ADMIN`: address of the proxy admin. The router is deployed using a `TransparentUpgradeableProxy` +- `ISM_SALT`: a salt for deploying the ISM the router uses. The provided in this repo is an `RoutingIsm` which allows the user indicate the ISM used when sending the message +- `ROUTER_IMPLEMENTATION`: the address of an existing implementation in the network +- `ISM`: the address of an existing implementation in the network +- `CUSTOM_HOOK`: some custom hook address to be set, address zero indicates the Mailbox default hook should be used + +For enrolling routers you have to run `yarn run:enrollRouters`. Make sure the following environment variable are set: +- `ROUTER_OWNER_PK`: the router's owner private key. Only the owner can enroll routers +- `ROUTER`: address of the local router +- `ROUTERS`: a list of routes addresses, separated by commas +- `DOMAINS`: the domains list of the routers to enroll, separated by commas + +## Example usage + +Running the example script `yarn run:interchainDeploy` would deploy a [TestDeployContract](./script/utils/TestDeployContract.sol) from the chain you set on `NETWORK` to the one you set on `DESTINATION_NETWORK` using the router set on `ROUTER` and the salt on `EXAMPLE_SALT` ## Installing Dependencies diff --git a/script/InterchainDeployExample.s.sol b/script/InterchainDeployExample.s.sol index 6efb421..c3913b0 100644 --- a/script/InterchainDeployExample.s.sol +++ b/script/InterchainDeployExample.s.sol @@ -14,11 +14,11 @@ contract InterchainDeployExample is Script { function run() public { uint256 ownerPrivateKey = vm.envUint("ROUTER_OWNER_PK"); address localRouter = vm.envAddress("ROUTER"); + uint32 destination = uint32(vm.envUint("DESTINATION")); + bytes32 salt = keccak256(abi.encodePacked(vm.envString("EXAMPLE_SALT"))); bytes memory bytecode = type(TestDeployContract).creationCode; - bytes32 salt = "testDeployContract.0.0.2"; bytes32 ism = TypeCasts.addressToBytes32(address(0)); - uint32 destination = uint32(11155111); bytes memory messageBody = InterchainCreate2FactoryMessage.encode( vm.addr(ownerPrivateKey), From 30b4ec0b95f5a86afada58ecf2fb8b2a86d2145d Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Mon, 9 Sep 2024 15:52:58 -0300 Subject: [PATCH 13/21] Linter --- README.md | 15 ++++++++++---- script/DeployRouter.s.sol | 14 +++++-------- script/EnrollRouters.s.sol | 7 +++---- script/InterchainDeployExample.s.sol | 30 +++++++++------------------- 4 files changed, 28 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 62114d1..51b6c41 100644 --- a/README.md +++ b/README.md @@ -17,19 +17,24 @@ Set the following environment variables required for running all the scripts, on - `NETWORK`: the name of the network you want to run the script - `API_KEY_ALCHEMY`: you Alchemy API key -If the network is not listed under the `rpc_endpoints` section of the [foundry.toml file](./foundry.toml) you'll have to add a new entry for it. +If the network is not listed under the `rpc_endpoints` section of the [foundry.toml file](./foundry.toml) you'll have to +add a new entry for it. + +For deploying the router you have to run the `yarn run:deployRouter`. Make sure the following environment variable are +set: -For deploying the router you have to run the `yarn run:deployRouter`. Make sure the following environment variable are set: - `DEPLOYER_PK`: deployer private key - `MAILBOX`: address of Hyperlane Mailbox contract on the chain - `ROUTER_OWNER`: address of the router owner - `PROXY_ADMIN`: address of the proxy admin. The router is deployed using a `TransparentUpgradeableProxy` -- `ISM_SALT`: a salt for deploying the ISM the router uses. The provided in this repo is an `RoutingIsm` which allows the user indicate the ISM used when sending the message +- `ISM_SALT`: a salt for deploying the ISM the router uses. The provided in this repo is an `RoutingIsm` which allows + the user indicate the ISM used when sending the message - `ROUTER_IMPLEMENTATION`: the address of an existing implementation in the network - `ISM`: the address of an existing implementation in the network - `CUSTOM_HOOK`: some custom hook address to be set, address zero indicates the Mailbox default hook should be used For enrolling routers you have to run `yarn run:enrollRouters`. Make sure the following environment variable are set: + - `ROUTER_OWNER_PK`: the router's owner private key. Only the owner can enroll routers - `ROUTER`: address of the local router - `ROUTERS`: a list of routes addresses, separated by commas @@ -37,7 +42,9 @@ For enrolling routers you have to run `yarn run:enrollRouters`. Make sure the fo ## Example usage -Running the example script `yarn run:interchainDeploy` would deploy a [TestDeployContract](./script/utils/TestDeployContract.sol) from the chain you set on `NETWORK` to the one you set on `DESTINATION_NETWORK` using the router set on `ROUTER` and the salt on `EXAMPLE_SALT` +Running the example script `yarn run:interchainDeploy` would deploy a +[TestDeployContract](./script/utils/TestDeployContract.sol) from the chain you set on `NETWORK` to the one you set on +`DESTINATION_NETWORK` using the router set on `ROUTER` and the salt on `EXAMPLE_SALT` ## Installing Dependencies diff --git a/script/DeployRouter.s.sol b/script/DeployRouter.s.sol index a2c512e..bc1d2fb 100644 --- a/script/DeployRouter.s.sol +++ b/script/DeployRouter.s.sol @@ -12,7 +12,6 @@ import { InterchainCreate2FactoryIsm } from "../src/InterchainCreate2FactoryIsm. /// @dev See the Solidity Scripting tutorial: https://book.getfoundry.sh/tutorials/solidity-scripting contract DeployRouter is Script { function run() public { - uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PK"); string memory ISM_SALT = vm.envString("ISM_SALT"); @@ -28,7 +27,7 @@ contract DeployRouter is Script { vm.startBroadcast(deployerPrivateKey); if (ism == address(0)) { - ism = address(new InterchainCreate2FactoryIsm{salt: ismSalt}(mailbox)); + ism = address(new InterchainCreate2FactoryIsm{ salt: ismSalt }(mailbox)); } if (routerImpl == address(0)) { @@ -38,17 +37,14 @@ contract DeployRouter is Script { TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( address(routerImpl), admin, - abi.encodeWithSelector( - InterchainCreate2FactoryRouter.initialize.selector, customHook, ism, owner - ) + abi.encodeWithSelector(InterchainCreate2FactoryRouter.initialize.selector, customHook, ism, owner) ); vm.stopBroadcast(); // solhint-disable-next-line no-console - console2.log('Proxy:', address(proxy)); - console2.log('Implementation:', routerImpl); - console2.log('ISM:', ism); - + console2.log("Proxy:", address(proxy)); + console2.log("Implementation:", routerImpl); + console2.log("ISM:", ism); } } diff --git a/script/EnrollRouters.s.sol b/script/EnrollRouters.s.sol index 621436f..f3ed9ca 100644 --- a/script/EnrollRouters.s.sol +++ b/script/EnrollRouters.s.sol @@ -18,15 +18,14 @@ contract EnrollRouters is Script { address localRouter = vm.envAddress("ROUTER"); if (routers.length != domains.length) { - revert('Invalid input'); + revert("Invalid input"); } vm.startBroadcast(ownerPrivateKey); - for (uint i = 0; i < routers.length; i++) { + for (uint256 i = 0; i < routers.length; i++) { InterchainCreate2FactoryRouter(localRouter).enrollRemoteRouter( - uint32(domains[i]), - TypeCasts.addressToBytes32(routers[i]) + uint32(domains[i]), TypeCasts.addressToBytes32(routers[i]) ); } diff --git a/script/InterchainDeployExample.s.sol b/script/InterchainDeployExample.s.sol index c3913b0..d80a8db 100644 --- a/script/InterchainDeployExample.s.sol +++ b/script/InterchainDeployExample.s.sol @@ -7,7 +7,7 @@ import { console2 } from "forge-std/src/console2.sol"; import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; import { InterchainCreate2FactoryRouter } from "src/InterchainCreate2FactoryRouter.sol"; import { InterchainCreate2FactoryMessage } from "src/libs/InterchainCreate2FactoryMessage.sol"; -import { TestDeployContract} from "./utils/TestDeployContract.sol"; +import { TestDeployContract } from "./utils/TestDeployContract.sol"; /// @dev See the Solidity Scripting tutorial: https://book.getfoundry.sh/tutorials/solidity-scripting contract InterchainDeployExample is Script { @@ -20,34 +20,22 @@ contract InterchainDeployExample is Script { bytes memory bytecode = type(TestDeployContract).creationCode; bytes32 ism = TypeCasts.addressToBytes32(address(0)); - bytes memory messageBody = InterchainCreate2FactoryMessage.encode( - vm.addr(ownerPrivateKey), - ism, - salt, - bytecode, - new bytes(0) - ); + bytes memory messageBody = + InterchainCreate2FactoryMessage.encode(vm.addr(ownerPrivateKey), ism, salt, bytecode, new bytes(0)); vm.startBroadcast(ownerPrivateKey); - uint256 gasPayment = InterchainCreate2FactoryRouter(localRouter).quoteGasPayment( - destination, - messageBody, - new bytes(0) - ); + uint256 gasPayment = + InterchainCreate2FactoryRouter(localRouter).quoteGasPayment(destination, messageBody, new bytes(0)); - bytes32 messageId = InterchainCreate2FactoryRouter(localRouter).deployContractAndInit{value: gasPayment}( - destination, - ism, - salt, - bytecode, - abi.encodeWithSelector(TestDeployContract.increment.selector) + bytes32 messageId = InterchainCreate2FactoryRouter(localRouter).deployContractAndInit{ value: gasPayment }( + destination, ism, salt, bytecode, abi.encodeWithSelector(TestDeployContract.increment.selector) ); vm.stopBroadcast(); - console2.log('Gas Payment:', gasPayment); - console2.log('messageId:'); + console2.log("Gas Payment:", gasPayment); + console2.log("messageId:"); console2.logBytes32(messageId); } } From 2727846fea1c87076ad057d1b54270fa640aeab7 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Mon, 9 Sep 2024 15:55:18 -0300 Subject: [PATCH 14/21] Remove bun from README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 51b6c41..56933bc 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,8 @@ Foundry typically uses git submodules to manage dependencies, but this template This is how to install dependencies: -1. Install the dependency using your preferred package manager, e.g. `bun install dependency-name` - - Use this syntax to install from GitHub: `bun install github:username/repo-name` +1. Install the dependency using your preferred package manager, e.g. `yarn install dependency-name` + - Use this syntax to install from GitHub: `yarn install github:username/repo-name` 2. Add a remapping for the dependency in [remappings.txt](./remappings.txt), e.g. `dependency-name=node_modules/dependency-name` From 8dd9c77bf2ac78c046679c1dd50fb9bf3879de28 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Wed, 11 Sep 2024 16:32:52 -0300 Subject: [PATCH 15/21] Use CreateX on deployment script --- .env.example | 1 + script/DeployRouter.s.sol | 35 +++++++-- script/utils/ICreateX.sol | 153 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 8 deletions(-) create mode 100644 script/utils/ICreateX.sol diff --git a/.env.example b/.env.example index a44751b..d09a511 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ export FOUNDRY_PROFILE="default" +export CREATEX_ADDRESS="the address of a CreateX present on all the chain you going to deploy" export NETWORK="network where the script is run" export API_KEY_ALCHEMY="YOUR_API_KEY_ALCHEMY" diff --git a/script/DeployRouter.s.sol b/script/DeployRouter.s.sol index bc1d2fb..f608711 100644 --- a/script/DeployRouter.s.sol +++ b/script/DeployRouter.s.sol @@ -5,6 +5,8 @@ import { Script } from "forge-std/src/Script.sol"; import { console2 } from "forge-std/src/console2.sol"; import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +// import { ICREATE3Factory } from "./utils/ICREATE3Factory.sol"; +import { ICreateX } from "./utils/ICreateX.sol"; import { InterchainCreate2FactoryRouter } from "../src/InterchainCreate2FactoryRouter.sol"; import { InterchainCreate2FactoryIsm } from "../src/InterchainCreate2FactoryIsm.sol"; @@ -15,29 +17,46 @@ contract DeployRouter is Script { uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PK"); string memory ISM_SALT = vm.envString("ISM_SALT"); + string memory ROUTER_SALT = vm.envString("ROUTER_SALT"); address mailbox = vm.envAddress("MAILBOX"); address admin = vm.envAddress("PROXY_ADMIN"); address owner = vm.envAddress("ROUTER_OWNER"); address routerImpl = vm.envOr("ROUTER_IMPLEMENTATION", address(0)); address ism = vm.envOr("ISM", address(0)); address customHook = vm.envOr("CUSTOM_HOOK", address(0)); - - bytes32 ismSalt = keccak256(abi.encodePacked(ISM_SALT, vm.addr(deployerPrivateKey))); + address createX = vm.envAddress("CREATEX_ADDRESS"); vm.startBroadcast(deployerPrivateKey); if (ism == address(0)) { - ism = address(new InterchainCreate2FactoryIsm{ salt: ismSalt }(mailbox)); + bytes32 ismSalt = keccak256(abi.encodePacked(ISM_SALT, vm.addr(deployerPrivateKey))); + bytes memory ismCreation = type(InterchainCreate2FactoryIsm).creationCode; + bytes memory ismBytecode = abi.encodePacked(ismCreation, abi.encode(mailbox)); + + ism = ICreateX(createX).deployCreate3(ismSalt, ismBytecode); } if (routerImpl == address(0)) { - routerImpl = address(new InterchainCreate2FactoryRouter(mailbox)); + bytes32 rImplSalt = keccak256(abi.encodePacked(ROUTER_SALT, "IMPLEMENTATION", vm.addr(deployerPrivateKey))); + bytes memory rImplCreation = type(InterchainCreate2FactoryRouter).creationCode; + bytes memory rImplBytecode = abi.encodePacked(rImplCreation, abi.encode(mailbox)); + + routerImpl = ICreateX(createX).deployCreate3(rImplSalt, rImplBytecode); } - TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy( - address(routerImpl), - admin, - abi.encodeWithSelector(InterchainCreate2FactoryRouter.initialize.selector, customHook, ism, owner) + bytes32 routerSalt = keccak256(abi.encodePacked(ROUTER_SALT, vm.addr(deployerPrivateKey))); + bytes memory routerCreation = type(TransparentUpgradeableProxy).creationCode; + bytes memory routerBytecode = abi.encodePacked( + routerCreation, + abi.encode( + address(routerImpl), + admin, + abi.encodeWithSelector(InterchainCreate2FactoryRouter.initialize.selector, customHook, ism, owner) + ) + ); + + TransparentUpgradeableProxy proxy = TransparentUpgradeableProxy( + payable(ICreateX(createX).deployCreate3(routerSalt, routerBytecode)) ); vm.stopBroadcast(); diff --git a/script/utils/ICreateX.sol b/script/utils/ICreateX.sol new file mode 100644 index 0000000..729034b --- /dev/null +++ b/script/utils/ICreateX.sol @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity ^0.8.4; + +/** + * @title CreateX Factory Interface Definition + * @author pcaversaccio (https://web.archive.org/web/20230921103111/https://pcaversaccio.com/) + * @custom:coauthor Matt Solomon (https://web.archive.org/web/20230921103335/https://mattsolomon.dev/) + */ +interface ICreateX { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TYPES */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + struct Values { + uint256 constructorAmount; + uint256 initCallAmount; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* EVENTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + event ContractCreation(address indexed newContract, bytes32 indexed salt); + event ContractCreation(address indexed newContract); + event Create3ProxyContractCreation(address indexed newContract, bytes32 indexed salt); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + error FailedContractCreation(address emitter); + error FailedContractInitialisation(address emitter, bytes revertData); + error InvalidSalt(address emitter); + error InvalidNonceValue(address emitter); + error FailedEtherTransfer(address emitter, bytes revertData); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CREATE */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function deployCreate(bytes memory initCode) external payable returns (address newContract); + + function deployCreateAndInit( + bytes memory initCode, + bytes memory data, + Values memory values, + address refundAddress + ) external payable returns (address newContract); + + function deployCreateAndInit( + bytes memory initCode, + bytes memory data, + Values memory values + ) external payable returns (address newContract); + + function deployCreateClone(address implementation, bytes memory data) external payable returns (address proxy); + + function computeCreateAddress(address deployer, uint256 nonce) external view returns (address computedAddress); + + function computeCreateAddress(uint256 nonce) external view returns (address computedAddress); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CREATE2 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function deployCreate2(bytes32 salt, bytes memory initCode) external payable returns (address newContract); + + function deployCreate2(bytes memory initCode) external payable returns (address newContract); + + function deployCreate2AndInit( + bytes32 salt, + bytes memory initCode, + bytes memory data, + Values memory values, + address refundAddress + ) external payable returns (address newContract); + + function deployCreate2AndInit( + bytes32 salt, + bytes memory initCode, + bytes memory data, + Values memory values + ) external payable returns (address newContract); + + function deployCreate2AndInit( + bytes memory initCode, + bytes memory data, + Values memory values, + address refundAddress + ) external payable returns (address newContract); + + function deployCreate2AndInit( + bytes memory initCode, + bytes memory data, + Values memory values + ) external payable returns (address newContract); + + function deployCreate2Clone( + bytes32 salt, + address implementation, + bytes memory data + ) external payable returns (address proxy); + + function deployCreate2Clone(address implementation, bytes memory data) external payable returns (address proxy); + + function computeCreate2Address( + bytes32 salt, + bytes32 initCodeHash, + address deployer + ) external pure returns (address computedAddress); + + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external view returns (address computedAddress); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CREATE3 */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + function deployCreate3(bytes32 salt, bytes memory initCode) external payable returns (address newContract); + + function deployCreate3(bytes memory initCode) external payable returns (address newContract); + + function deployCreate3AndInit( + bytes32 salt, + bytes memory initCode, + bytes memory data, + Values memory values, + address refundAddress + ) external payable returns (address newContract); + + function deployCreate3AndInit( + bytes32 salt, + bytes memory initCode, + bytes memory data, + Values memory values + ) external payable returns (address newContract); + + function deployCreate3AndInit( + bytes memory initCode, + bytes memory data, + Values memory values, + address refundAddress + ) external payable returns (address newContract); + + function deployCreate3AndInit( + bytes memory initCode, + bytes memory data, + Values memory values + ) external payable returns (address newContract); + + function computeCreate3Address(bytes32 salt, address deployer) external pure returns (address computedAddress); + + function computeCreate3Address(bytes32 salt) external view returns (address computedAddress); +} From f94a273fbe04e9b9d798c10df36ecd9051b03b5b Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Wed, 11 Sep 2024 16:46:05 -0300 Subject: [PATCH 16/21] Enroll routers by domain with the same address --- src/InterchainCreate2FactoryRouter.sol | 37 ++++++++++++++++- test/InterchainCreate2FactoryRouter.t.sol | 48 +++++++++++++++++++++-- 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol index 9034872..120b3e6 100644 --- a/src/InterchainCreate2FactoryRouter.sol +++ b/src/InterchainCreate2FactoryRouter.sol @@ -40,16 +40,51 @@ contract InterchainCreate2FactoryRouter is Router { /** * @notice Initializes the contract with HyperlaneConnectionClient contracts + * @param _domains The domains of the remote Application Routers * @param _customHook used by the Router to set the hook to override with * @param _interchainSecurityModule The address of the local ISM contract * @param _owner The address with owner privileges */ - function initialize(address _customHook, address _interchainSecurityModule, address _owner) external initializer { + function initialize( + uint32[] calldata _domains, + address _customHook, + address _interchainSecurityModule, + address _owner + ) external initializer { _MailboxClient_initialize(_customHook, _interchainSecurityModule, _owner); + + uint256 length = _domains.length; + for (uint256 i = 0; i < length; i += 1) { + _enrollRemoteRouter(_domains[i], TypeCasts.addressToBytes32(address(this))); + } } // ============ External Functions ============ + /** + * @notice Register the address of a Router contract with the same address as this for the same Application on a + * remote chain + * @param _domain The domain of the remote Application Router + */ + function enrollRemoteDomain( + uint32 _domain + ) external virtual onlyOwner { + _enrollRemoteRouter(_domain, TypeCasts.addressToBytes32(address(this))); + } + + /** + * @notice Batch version of `enrollRemoteDomain + * @param _domains The domains of the remote Application Routers + */ + function enrollRemoteDomains( + uint32[] calldata _domains + ) external virtual onlyOwner { + uint256 length = _domains.length; + for (uint256 i = 0; i < length; i += 1) { + _enrollRemoteRouter(_domains[i], TypeCasts.addressToBytes32(address(this))); + } + } + /** * @notice Deploys a contract on the `_destination` chain * @param _destination The remote domain diff --git a/test/InterchainCreate2FactoryRouter.t.sol b/test/InterchainCreate2FactoryRouter.t.sol index 9d727b9..a11569b 100644 --- a/test/InterchainCreate2FactoryRouter.t.sol +++ b/test/InterchainCreate2FactoryRouter.t.sol @@ -73,6 +73,7 @@ contract InterchainCreate2FactoryRouterBase is Test { // address internal sender = makeAddr("sender"); function deployProxiedRouter( + uint32[] memory _domains, MockMailbox _mailbox, IPostDispatchHook _customHook, IInterchainSecurityModule _ism, @@ -87,7 +88,7 @@ contract InterchainCreate2FactoryRouterBase is Test { address(implementation), admin, abi.encodeWithSelector( - InterchainCreate2FactoryRouter.initialize.selector, address(_customHook), address(_ism), _owner + InterchainCreate2FactoryRouter.initialize.selector, _domains, address(_customHook), address(_ism), _owner ) ); @@ -104,9 +105,11 @@ contract InterchainCreate2FactoryRouterBase is Test { testIsm = new TestIsm(); - originRouter = deployProxiedRouter(environment.mailboxes(origin), environment.igps(destination), ism, owner); + uint32[] memory domains = new uint32[](0); + + originRouter = deployProxiedRouter(domains, environment.mailboxes(origin), environment.igps(destination), ism, owner); destinationRouter = - deployProxiedRouter(environment.mailboxes(destination), environment.igps(destination), ism, owner); + deployProxiedRouter(domains, environment.mailboxes(destination), environment.igps(destination), ism, owner); environment.mailboxes(origin).setDefaultHook(address(igp)); @@ -131,6 +134,45 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas _; } + function testFuzz_enrollRemoteDoamain(uint32 domain) public { + + // act + vm.prank(owner); + originRouter.enrollRemoteDomain(domain); + + // assert + bytes32 actualRouter = originRouter.routers(domain); + assertEq(actualRouter, TypeCasts.addressToBytes32(address(originRouter))); + } + + + function testFuzz_enrollRemoteDoamains(uint8 count, uint32 domain) public { + vm.assume(count > 0 && count < domain); + + // arrange + // count - # of domains and routers + uint32[] memory domains = new uint32[](count); + for (uint256 i = 0; i < count; i++) { + domains[i] = domain - uint32(i); + } + + // act + vm.prank(owner); + originRouter.enrollRemoteDomains(domains); + + // assert + uint32[] memory actualDomains = originRouter.domains(); + assertEq(actualDomains.length, domains.length); + assertEq(abi.encode(originRouter.domains()), abi.encode(domains)); + + for (uint256 i = 0; i < count; i++) { + bytes32 actualRouter = originRouter.routers(domains[i]); + + assertEq(actualRouter, TypeCasts.addressToBytes32(address(originRouter))); + assertEq(actualDomains[i], domains[i]); + } + } + function testFuzz_enrollRemoteRouters(uint8 count, uint32 domain, bytes32 router) public { vm.assume(count > 0 && count < uint256(router) && count < domain); From b164504e2e30e0709b9a251ffe13450d1bb93a99 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Thu, 12 Sep 2024 09:19:12 -0300 Subject: [PATCH 17/21] Lint --- script/DeployRouter.s.sol | 11 ++-- script/utils/ICreateX.sol | 68 ++++++++++++++++++----- src/InterchainCreate2FactoryRouter.sol | 13 ++--- test/InterchainCreate2FactoryRouter.t.sol | 11 ++-- 4 files changed, 73 insertions(+), 30 deletions(-) diff --git a/script/DeployRouter.s.sol b/script/DeployRouter.s.sol index f608711..9e7e424 100644 --- a/script/DeployRouter.s.sol +++ b/script/DeployRouter.s.sol @@ -49,15 +49,14 @@ contract DeployRouter is Script { bytes memory routerBytecode = abi.encodePacked( routerCreation, abi.encode( - address(routerImpl), - admin, - abi.encodeWithSelector(InterchainCreate2FactoryRouter.initialize.selector, customHook, ism, owner) + address(routerImpl), + admin, + abi.encodeWithSelector(InterchainCreate2FactoryRouter.initialize.selector, customHook, ism, owner) ) ); - TransparentUpgradeableProxy proxy = TransparentUpgradeableProxy( - payable(ICreateX(createX).deployCreate3(routerSalt, routerBytecode)) - ); + TransparentUpgradeableProxy proxy = + TransparentUpgradeableProxy(payable(ICreateX(createX).deployCreate3(routerSalt, routerBytecode))); vm.stopBroadcast(); diff --git a/script/utils/ICreateX.sol b/script/utils/ICreateX.sol index 729034b..474784f 100644 --- a/script/utils/ICreateX.sol +++ b/script/utils/ICreateX.sol @@ -45,13 +45,19 @@ interface ICreateX { bytes memory data, Values memory values, address refundAddress - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function deployCreateAndInit( bytes memory initCode, bytes memory data, Values memory values - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function deployCreateClone(address implementation, bytes memory data) external payable returns (address proxy); @@ -73,33 +79,48 @@ interface ICreateX { bytes memory data, Values memory values, address refundAddress - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function deployCreate2AndInit( bytes32 salt, bytes memory initCode, bytes memory data, Values memory values - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function deployCreate2AndInit( bytes memory initCode, bytes memory data, Values memory values, address refundAddress - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function deployCreate2AndInit( bytes memory initCode, bytes memory data, Values memory values - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function deployCreate2Clone( bytes32 salt, address implementation, bytes memory data - ) external payable returns (address proxy); + ) + external + payable + returns (address proxy); function deployCreate2Clone(address implementation, bytes memory data) external payable returns (address proxy); @@ -107,9 +128,18 @@ interface ICreateX { bytes32 salt, bytes32 initCodeHash, address deployer - ) external pure returns (address computedAddress); + ) + external + pure + returns (address computedAddress); - function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) external view returns (address computedAddress); + function computeCreate2Address( + bytes32 salt, + bytes32 initCodeHash + ) + external + view + returns (address computedAddress); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CREATE3 */ @@ -125,27 +155,39 @@ interface ICreateX { bytes memory data, Values memory values, address refundAddress - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function deployCreate3AndInit( bytes32 salt, bytes memory initCode, bytes memory data, Values memory values - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function deployCreate3AndInit( bytes memory initCode, bytes memory data, Values memory values, address refundAddress - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function deployCreate3AndInit( bytes memory initCode, bytes memory data, Values memory values - ) external payable returns (address newContract); + ) + external + payable + returns (address newContract); function computeCreate3Address(bytes32 salt, address deployer) external pure returns (address computedAddress); diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol index 120b3e6..79965b2 100644 --- a/src/InterchainCreate2FactoryRouter.sol +++ b/src/InterchainCreate2FactoryRouter.sol @@ -50,7 +50,10 @@ contract InterchainCreate2FactoryRouter is Router { address _customHook, address _interchainSecurityModule, address _owner - ) external initializer { + ) + external + initializer + { _MailboxClient_initialize(_customHook, _interchainSecurityModule, _owner); uint256 length = _domains.length; @@ -66,9 +69,7 @@ contract InterchainCreate2FactoryRouter is Router { * remote chain * @param _domain The domain of the remote Application Router */ - function enrollRemoteDomain( - uint32 _domain - ) external virtual onlyOwner { + function enrollRemoteDomain(uint32 _domain) external virtual onlyOwner { _enrollRemoteRouter(_domain, TypeCasts.addressToBytes32(address(this))); } @@ -76,9 +77,7 @@ contract InterchainCreate2FactoryRouter is Router { * @notice Batch version of `enrollRemoteDomain * @param _domains The domains of the remote Application Routers */ - function enrollRemoteDomains( - uint32[] calldata _domains - ) external virtual onlyOwner { + function enrollRemoteDomains(uint32[] calldata _domains) external virtual onlyOwner { uint256 length = _domains.length; for (uint256 i = 0; i < length; i += 1) { _enrollRemoteRouter(_domains[i], TypeCasts.addressToBytes32(address(this))); diff --git a/test/InterchainCreate2FactoryRouter.t.sol b/test/InterchainCreate2FactoryRouter.t.sol index a11569b..50b1398 100644 --- a/test/InterchainCreate2FactoryRouter.t.sol +++ b/test/InterchainCreate2FactoryRouter.t.sol @@ -88,7 +88,11 @@ contract InterchainCreate2FactoryRouterBase is Test { address(implementation), admin, abi.encodeWithSelector( - InterchainCreate2FactoryRouter.initialize.selector, _domains, address(_customHook), address(_ism), _owner + InterchainCreate2FactoryRouter.initialize.selector, + _domains, + address(_customHook), + address(_ism), + _owner ) ); @@ -107,7 +111,8 @@ contract InterchainCreate2FactoryRouterBase is Test { uint32[] memory domains = new uint32[](0); - originRouter = deployProxiedRouter(domains, environment.mailboxes(origin), environment.igps(destination), ism, owner); + originRouter = + deployProxiedRouter(domains, environment.mailboxes(origin), environment.igps(destination), ism, owner); destinationRouter = deployProxiedRouter(domains, environment.mailboxes(destination), environment.igps(destination), ism, owner); @@ -135,7 +140,6 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas } function testFuzz_enrollRemoteDoamain(uint32 domain) public { - // act vm.prank(owner); originRouter.enrollRemoteDomain(domain); @@ -145,7 +149,6 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertEq(actualRouter, TypeCasts.addressToBytes32(address(originRouter))); } - function testFuzz_enrollRemoteDoamains(uint8 count, uint32 domain) public { vm.assume(count > 0 && count < domain); From 69292109a1044af48ca2b1cf8f846dc9103b1e0b Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Thu, 12 Sep 2024 09:22:01 -0300 Subject: [PATCH 18/21] Lint --- script/utils/ICreateX.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/utils/ICreateX.sol b/script/utils/ICreateX.sol index 474784f..076fa05 100644 --- a/script/utils/ICreateX.sol +++ b/script/utils/ICreateX.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-only -pragma solidity ^0.8.4; +pragma solidity 0.8.25; /** * @title CreateX Factory Interface Definition From ff36ae61ba6c7deeb26cee17fde685f3f5709afa Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Fri, 13 Sep 2024 15:09:25 -0300 Subject: [PATCH 19/21] Add quoteGasPaymentWithOverrides --- script/InterchainDeployExample.s.sol | 2 +- src/InterchainCreate2FactoryRouter.sol | 148 ++++++++++++++-------- test/InterchainCreate2FactoryRouter.t.sol | 43 ++++--- 3 files changed, 126 insertions(+), 67 deletions(-) diff --git a/script/InterchainDeployExample.s.sol b/script/InterchainDeployExample.s.sol index d80a8db..bbf70f2 100644 --- a/script/InterchainDeployExample.s.sol +++ b/script/InterchainDeployExample.s.sol @@ -28,7 +28,7 @@ contract InterchainDeployExample is Script { uint256 gasPayment = InterchainCreate2FactoryRouter(localRouter).quoteGasPayment(destination, messageBody, new bytes(0)); - bytes32 messageId = InterchainCreate2FactoryRouter(localRouter).deployContractAndInit{ value: gasPayment }( + bytes32 messageId = InterchainCreate2FactoryRouter(localRouter).deployContract{ value: gasPayment }( destination, ism, salt, bytecode, abi.encodeWithSelector(TestDeployContract.increment.selector) ); diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol index 79965b2..248b749 100644 --- a/src/InterchainCreate2FactoryRouter.sol +++ b/src/InterchainCreate2FactoryRouter.sol @@ -5,6 +5,7 @@ pragma solidity 0.8.25; import { InterchainCreate2FactoryMessage } from "./libs/InterchainCreate2FactoryMessage.sol"; // ============ External Imports ============ +import { IPostDispatchHook } from "@hyperlane-xyz/interfaces/hooks/IPostDispatchHook.sol"; import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; import { Router } from "@hyperlane-xyz/client/Router.sol"; import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol"; @@ -28,7 +29,9 @@ contract InterchainCreate2FactoryRouter is Router { // ============ Events ============ - event RemoteDeployDispatched(uint32 indexed destination, address indexed owner, uint32 _destination, bytes32 ism); + event RemoteDeployDispatched( + uint32 indexed destination, bytes32 indexed router, address indexed owner, uint32 _destination, bytes32 ism + ); event Deployed(bytes32 indexed bytecodeHash, bytes32 indexed salt, address indexed deployedAddress); @@ -90,20 +93,22 @@ contract InterchainCreate2FactoryRouter is Router { * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM * @param _salt The salt used for deploying the contract with CREATE2 * @param _bytecode The bytecode of the contract to deploy + * @param _initCode The initialization that is called after the contract is deployed, empty for no initialization */ function deployContract( uint32 _destination, bytes32 _ism, bytes32 _salt, - bytes memory _bytecode + bytes memory _bytecode, + bytes memory _initCode ) external payable returns (bytes32) { - bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, new bytes(0)); + bytes32 _router = _mustHaveRemoteRouter(_destination); - return _dispatchMessage(_destination, _ism, _body, ""); + return deployContractWithOverrides(_destination, _router, _ism, _salt, address(hook), _bytecode, _initCode); } /** @@ -112,6 +117,7 @@ contract InterchainCreate2FactoryRouter is Router { * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM * @param _salt The salt used for deploying the contract with CREATE2 * @param _bytecode The bytecode of the contract to deploy + * @param _initCode The initialization that is called after the contract is deployed, empty for no initialization * @param _hookMetadata The hook metadata to override with for the hook set by the owner */ function deployContract( @@ -119,76 +125,52 @@ contract InterchainCreate2FactoryRouter is Router { bytes32 _ism, bytes32 _salt, bytes memory _bytecode, + bytes memory _initCode, bytes memory _hookMetadata ) external payable returns (bytes32) { - bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, new bytes(0)); - - return _dispatchMessage(_destination, _ism, _body, _hookMetadata); - } - - /** - * @notice Deploys and initialize a contract on the `_destination` chain - * @param _destination The remote domain - * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM - * @param _salt The salt used for deploying the contract with CREATE2 - * @param _bytecode The bytecode of the contract to deploy - * @param _initCode The initialization that is called after the contract is deployed - */ - function deployContractAndInit( - uint32 _destination, - bytes32 _ism, - bytes32 _salt, - bytes memory _bytecode, - bytes memory _initCode - ) - external - payable - returns (bytes32) - { - bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); + bytes32 _router = _mustHaveRemoteRouter(_destination); - return _dispatchMessage(_destination, _ism, _body, ""); + return deployContractWithOverrides( + _destination, _router, _ism, _salt, address(hook), _bytecode, _initCode, _hookMetadata + ); } /** - * @notice Deploys and initialize a contract on the `_destination` chain with hook metadata - * @param _destination The remote domain - * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM - * @param _salt The salt used for deploying the contract with CREATE2 - * @param _bytecode The bytecode of the contract to deploy - * @param _initCode The initialization that is called after the contract is deployed + * @notice Returns the gas payment required to dispatch a given messageBody to the given domain's router with gas + * limit override. + * @param _destination The domain of the destination router. + * @param _messageBody The message body to be dispatched. * @param _hookMetadata The hook metadata to override with for the hook set by the owner */ - function deployContractAndInit( + function quoteGasPayment( uint32 _destination, - bytes32 _ism, - bytes32 _salt, - bytes memory _bytecode, - bytes memory _initCode, + bytes memory _messageBody, bytes memory _hookMetadata ) external - payable - returns (bytes32) + view + returns (uint256 _gasPayment) { - bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); - - return _dispatchMessage(_destination, _ism, _body, _hookMetadata); + return _Router_quoteDispatch(_destination, _messageBody, _hookMetadata, address(hook)); } /** * @notice Returns the gas payment required to dispatch a given messageBody to the given domain's router with gas * limit override. * @param _destination The domain of the destination router. + * @param _router The destination router. + * @param _hook The a hook to override the default hook. * @param _messageBody The message body to be dispatched. * @param _hookMetadata The hook metadata to override with for the hook set by the owner */ - function quoteGasPayment( + function quoteGasPaymentWithOverrides( uint32 _destination, + bytes32 _router, + address _hook, bytes memory _messageBody, bytes memory _hookMetadata ) @@ -196,7 +178,7 @@ contract InterchainCreate2FactoryRouter is Router { view returns (uint256 _gasPayment) { - return _Router_quoteDispatch(_destination, _messageBody, _hookMetadata, address(hook)); + return mailbox.quoteDispatch(_destination, _router, _messageBody, _hookMetadata, IPostDispatchHook(_hook)); } /** @@ -220,6 +202,66 @@ contract InterchainCreate2FactoryRouter is Router { ); } + // ============ Public Functions ============ + + /** + * @notice Deploys and initialize a contract on the `_destination` chain with hook metadata + * @param _destination The remote domain + * @param _router The remote router address + * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM + * @param _salt The salt used for deploying the contract with CREATE2 + * @param _hook The address hook to override the default hook + * @param _bytecode The bytecode of the contract to deploy + * @param _initCode The initialization that is called after the contract is deployed + */ + function deployContractWithOverrides( + uint32 _destination, + bytes32 _router, + bytes32 _ism, + bytes32 _salt, + address _hook, + bytes memory _bytecode, + bytes memory _initCode + ) + public + payable + returns (bytes32) + { + bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); + + return _dispatchMessage(_destination, _router, _ism, _hook, _body, new bytes(0)); + } + + /** + * @notice Deploys and initialize a contract on the `_destination` chain with hook metadata + * @param _destination The remote domain + * @param _router The remote router address + * @param _ism The address of the remote ISM, zero address for using the remote mailbox default ISM + * @param _salt The salt used for deploying the contract with CREATE2 + * @param _hook The address hook to override the default hook + * @param _bytecode The bytecode of the contract to deploy + * @param _initCode The initialization that is called after the contract is deployed + * @param _hookMetadata The hook metadata to override with for the hook set by the owner + */ + function deployContractWithOverrides( + uint32 _destination, + bytes32 _router, + bytes32 _ism, + bytes32 _salt, + address _hook, + bytes memory _bytecode, + bytes memory _initCode, + bytes memory _hookMetadata + ) + public + payable + returns (bytes32) + { + bytes memory _body = InterchainCreate2FactoryMessage.encode(msg.sender, _ism, _salt, _bytecode, _initCode); + + return _dispatchMessage(_destination, _router, _ism, _hook, _body, _hookMetadata); + } + // ============ Internal Functions ============ /** @@ -242,22 +284,28 @@ contract InterchainCreate2FactoryRouter is Router { /** * @notice Dispatches an InterchainCreate2FactoryMessage to the remote router * @param _destination The remote domain + * @param _router The remote origin InterchainCreate2FactoryRouter * @param _ism The address of the remote ISM + * @param _hook The address hook * @param _messageBody The InterchainCreate2FactoryMessage body * @param _hookMetadata The hook metadata to override with for the hook set by the owner */ function _dispatchMessage( uint32 _destination, + bytes32 _router, bytes32 _ism, + address _hook, bytes memory _messageBody, bytes memory _hookMetadata ) private returns (bytes32) { - emit RemoteDeployDispatched(_destination, msg.sender, _destination, _ism); + emit RemoteDeployDispatched(_destination, _router, msg.sender, _destination, _ism); - return _Router_dispatch(_destination, msg.value, _messageBody, _hookMetadata, address(hook)); + return mailbox.dispatch{ value: msg.value }( + _destination, _router, _messageBody, _hookMetadata, IPostDispatchHook(_hook) + ); } /** diff --git a/test/InterchainCreate2FactoryRouter.t.sol b/test/InterchainCreate2FactoryRouter.t.sol index 50b1398..464738b 100644 --- a/test/InterchainCreate2FactoryRouter.t.sol +++ b/test/InterchainCreate2FactoryRouter.t.sol @@ -149,7 +149,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertEq(actualRouter, TypeCasts.addressToBytes32(address(originRouter))); } - function testFuzz_enrollRemoteDoamains(uint8 count, uint32 domain) public { + function testFuzz_enrollRemoteDomains(uint8 count, uint32 domain) public { vm.assume(count > 0 && count < domain); // arrange @@ -215,6 +215,17 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertEq(originRouter.quoteGasPayment(destination, messageBody, new bytes(0)), gasPaymentQuote); } + // TODO + function test_quoteGasPaymentWithOverrides() public enrollRouters { + // arrange + bytes memory messageBody = InterchainCreate2FactoryMessage.encode( + address(1), TypeCasts.addressToBytes32(address(0)), "", new bytes(0), new bytes(0) + ); + + // assert + assertEq(originRouter.quoteGasPayment(destination, messageBody, new bytes(0)), gasPaymentQuote); + } + function test_quoteGasPayment_gasLimitOverride() public enrollRouters { // arrange bytes memory messageBody = InterchainCreate2FactoryMessage.encode( @@ -302,7 +313,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); vm.expectRevert("No router enrolled for domain: 2"); - originRouter.deployContract{ value: gasPaymentQuote }(destination, "", salt, bytecode); + originRouter.deployContract{ value: gasPaymentQuote }(destination, "", salt, bytecode, new bytes(0)); } function testFuzz_deployContract_defaultISM(address sender, bytes32 salt) public enrollRouters { @@ -316,7 +327,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{ value: gasPaymentQuote }(destination, "", salt, bytecode); + originRouter.deployContract{ value: gasPaymentQuote }(destination, "", salt, bytecode, new bytes(0)); // assert uint256 balanceAfter = address(sender).balance; @@ -338,7 +349,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{ value: gasPaymentQuote }(destination, "", salt, bytecode, initCode); + originRouter.deployContract{ value: gasPaymentQuote }(destination, "", salt, bytecode, initCode); // assert uint256 balanceAfter = address(sender).balance; @@ -369,7 +380,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{ value: payment }(destination, "", salt, bytecode, metadata); + originRouter.deployContract{ value: payment }(destination, "", salt, bytecode, new bytes(0), metadata); // assert uint256 balanceAfter = address(sender).balance; @@ -402,7 +413,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{ value: payment }(destination, "", salt, bytecode, initCode, metadata); + originRouter.deployContract{ value: payment }(destination, "", salt, bytecode, initCode, metadata); // assert uint256 balanceAfter = address(sender).balance; @@ -432,7 +443,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); vm.expectRevert("IGP: insufficient interchain gas payment"); - originRouter.deployContract{ value: payment }(destination, "", salt, bytecode, metadata); + originRouter.deployContract{ value: payment }(destination, "", salt, bytecode, new bytes(0), metadata); } function testFuzz_deployContractAndInit_defaultISM_reverts_underpayment( @@ -458,7 +469,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas vm.prank(sender); vm.expectRevert("IGP: insufficient interchain gas payment"); - originRouter.deployContractAndInit{ value: payment }(destination, "", salt, bytecode, initCode, metadata); + originRouter.deployContract{ value: payment }(destination, "", salt, bytecode, initCode, metadata); } function testFuzz_deployContract_paramISM(address sender, bytes32 salt) public enrollRouters { @@ -472,7 +483,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{ value: gasPaymentQuote }(destination, testIsmB32, salt, bytecode); + originRouter.deployContract{ value: gasPaymentQuote }(destination, testIsmB32, salt, bytecode, new bytes(0)); // assert uint256 balanceAfter = address(sender).balance; @@ -493,7 +504,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{ value: gasPaymentQuote }(destination, testIsmB32, salt, bytecode, initCode); + originRouter.deployContract{ value: gasPaymentQuote }(destination, testIsmB32, salt, bytecode, initCode); // assert uint256 balanceAfter = address(sender).balance; @@ -523,7 +534,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{ value: payment }(destination, testIsmB32, salt, bytecode, metadata); + originRouter.deployContract{ value: payment }(destination, testIsmB32, salt, bytecode, new bytes(0), metadata); // assert uint256 balanceAfter = address(sender).balance; @@ -555,9 +566,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{ value: payment }( - destination, testIsmB32, salt, bytecode, initCode, metadata - ); + originRouter.deployContract{ value: payment }(destination, testIsmB32, salt, bytecode, initCode, metadata); // assert uint256 balanceAfter = address(sender).balance; @@ -578,7 +587,7 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContract{ value: gasPaymentQuote }(destination, failingIsm, salt, bytecode); + originRouter.deployContract{ value: gasPaymentQuote }(destination, failingIsm, salt, bytecode, new bytes(0)); // assert vm.expectRevert(bytes(failureMessage)); @@ -600,10 +609,12 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas bytes memory initCode = abi.encodeWithSelector(SomeContract.someFunction.selector); vm.prank(sender); - originRouter.deployContractAndInit{ value: gasPaymentQuote }(destination, failingIsm, salt, bytecode, initCode); + originRouter.deployContract{ value: gasPaymentQuote }(destination, failingIsm, salt, bytecode, initCode); // assert vm.expectRevert(bytes(failureMessage)); environment.processNextPendingMessage(); } + + // TODO - add tests for deployContractWithOverrides } From 59fb3b57df1136dcedff5417c0b1e641a51e8a7d Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Fri, 13 Sep 2024 17:54:41 -0300 Subject: [PATCH 20/21] Add tests for override functions --- src/InterchainCreate2FactoryRouter.sol | 40 +++++--- test/InterchainCreate2FactoryRouter.t.sol | 107 ++++++++++++++++++++-- 2 files changed, 124 insertions(+), 23 deletions(-) diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol index 248b749..5045bcb 100644 --- a/src/InterchainCreate2FactoryRouter.sol +++ b/src/InterchainCreate2FactoryRouter.sol @@ -139,6 +139,29 @@ contract InterchainCreate2FactoryRouter is Router { ); } + /** + * @notice Handles dispatched messages by deploying the contract using the data from an incoming message + * @param _message The message containing the data sent by the remote router + * @dev Does not need to be onlyRemoteRouter, as this application is designed + * to receive messages from untrusted remote contracts. + */ + function handle( + uint32, + bytes32, + bytes calldata _message + ) external payable override onlyMailbox { + (bytes32 _sender,, bytes32 _salt, bytes memory _bytecode, bytes memory _initCode) = + InterchainCreate2FactoryMessage.decode(_message); + + address deployedAddress_ = _deploy(_bytecode, _getSalt(_sender, _salt)); + + if (_initCode.length > 0) { + // solhint-disable-next-line avoid-low-level-calls + (bool success,) = deployedAddress_.call(_initCode); + require(success, "failed to init"); + } + } + /** * @notice Returns the gas payment required to dispatch a given messageBody to the given domain's router with gas * limit override. @@ -265,22 +288,13 @@ contract InterchainCreate2FactoryRouter is Router { // ============ Internal Functions ============ /** - * @notice Deploys the contract using the data from an incoming message - * @param _message The message containing the data sent by the remote router + * @dev Required for use of Router, compiler will not include this function in the bytecode */ - function _handle(uint32, bytes32, bytes calldata _message) internal override { - (bytes32 _sender,, bytes32 _salt, bytes memory _bytecode, bytes memory _initCode) = - InterchainCreate2FactoryMessage.decode(_message); - - address deployedAddress_ = _deploy(_bytecode, _getSalt(_sender, _salt)); - - if (_initCode.length > 0) { - // solhint-disable-next-line avoid-low-level-calls - (bool success,) = deployedAddress_.call(_initCode); - require(success, "failed to init"); - } + function _handle(uint32, bytes32, bytes calldata) internal pure override { + assert(false); } + /** * @notice Dispatches an InterchainCreate2FactoryMessage to the remote router * @param _destination The remote domain diff --git a/test/InterchainCreate2FactoryRouter.t.sol b/test/InterchainCreate2FactoryRouter.t.sol index 464738b..c964477 100644 --- a/test/InterchainCreate2FactoryRouter.t.sol +++ b/test/InterchainCreate2FactoryRouter.t.sol @@ -12,9 +12,9 @@ import { MockMailbox } from "@hyperlane-xyz/mock/MockMailbox.sol"; import { MockHyperlaneEnvironment } from "@hyperlane-xyz/mock/MockHyperlaneEnvironment.sol"; import { TypeCasts } from "@hyperlane-xyz/libs/TypeCasts.sol"; import { IInterchainSecurityModule } from "@hyperlane-xyz/interfaces/IInterchainSecurityModule.sol"; -import { TestInterchainGasPaymaster } from "@hyperlane-xyz/test/TestInterchainGasPaymaster.sol"; import { IPostDispatchHook } from "@hyperlane-xyz/interfaces/hooks/IPostDispatchHook.sol"; import { TestIsm } from "@hyperlane-xyz/test/TestIsm.sol"; +import { InterchainGasPaymaster } from "@hyperlane-xyz/hooks/igp/InterchainGasPaymaster.sol"; import { InterchainCreate2FactoryRouter } from "src/InterchainCreate2FactoryRouter.sol"; import { InterchainCreate2FactoryIsm } from "src/InterchainCreate2FactoryIsm.sol"; @@ -44,6 +44,29 @@ contract FailingIsm is IInterchainSecurityModule { } } +contract TestInterchainGasPaymaster is InterchainGasPaymaster { + uint256 public gasPrice = 10; + + constructor() { + initialize(msg.sender, msg.sender); + } + + function quoteGasPayment( + uint32, + uint256 gasAmount + ) public view override returns (uint256) { + return gasPrice * gasAmount; + } + + function setGasPrice(uint256 _gasPrice) public { + gasPrice = _gasPrice; + } + + function getDefaultGasUsage() public pure returns (uint256) { + return DEFAULT_GAS_USAGE; + } +} + contract InterchainCreate2FactoryRouterBase is Test { using TypeCasts for address; @@ -56,16 +79,20 @@ contract InterchainCreate2FactoryRouterBase is Test { uint32 internal destination = 2; TestInterchainGasPaymaster internal igp; + TestInterchainGasPaymaster internal igpOverride; InterchainCreate2FactoryIsm internal ism; InterchainCreate2FactoryRouter internal originRouter; InterchainCreate2FactoryRouter internal destinationRouter; + InterchainCreate2FactoryRouter internal destinationRouterOverride; TestIsm internal testIsm; bytes32 internal testIsmB32; bytes32 internal originRouterB32; bytes32 internal destinationRouterB32; + bytes32 internal destinationRouterOverrideB32; uint256 gasPaymentQuote; + uint256 gasPaymentQuoteOverride; uint256 internal constant GAS_LIMIT_OVERRIDE = 60_000; address internal admin = makeAddr("admin"); @@ -103,6 +130,8 @@ contract InterchainCreate2FactoryRouterBase is Test { environment = new MockHyperlaneEnvironment(origin, destination); igp = new TestInterchainGasPaymaster(); + igpOverride = new TestInterchainGasPaymaster(); + gasPaymentQuote = igp.quoteGasPayment(destination, igp.getDefaultGasUsage()); ism = new InterchainCreate2FactoryIsm(address(environment.mailboxes(destination))); @@ -116,10 +145,14 @@ contract InterchainCreate2FactoryRouterBase is Test { destinationRouter = deployProxiedRouter(domains, environment.mailboxes(destination), environment.igps(destination), ism, owner); + destinationRouterOverride = + deployProxiedRouter(domains, environment.mailboxes(destination), environment.igps(destination), ism, owner); + environment.mailboxes(origin).setDefaultHook(address(igp)); originRouterB32 = TypeCasts.addressToBytes32(address(originRouter)); destinationRouterB32 = TypeCasts.addressToBytes32(address(destinationRouter)); + destinationRouterOverrideB32 = TypeCasts.addressToBytes32(address(destinationRouterOverride)); testIsmB32 = TypeCasts.addressToBytes32(address(testIsm)); } @@ -215,15 +248,20 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertEq(originRouter.quoteGasPayment(destination, messageBody, new bytes(0)), gasPaymentQuote); } - // TODO - function test_quoteGasPaymentWithOverrides() public enrollRouters { + function test_quoteGasPaymentWithOverrides(uint256 _gasPriceOverride) public enrollRouters { + vm.assume(_gasPriceOverride < type(uint16).max); + // arrange + igpOverride.setGasPrice(_gasPriceOverride); bytes memory messageBody = InterchainCreate2FactoryMessage.encode( address(1), TypeCasts.addressToBytes32(address(0)), "", new bytes(0), new bytes(0) ); // assert - assertEq(originRouter.quoteGasPayment(destination, messageBody, new bytes(0)), gasPaymentQuote); + assertEq( + originRouter.quoteGasPaymentWithOverrides(destination, destinationRouterB32, address(igpOverride), messageBody, new bytes(0)), + igpOverride.quoteGasPayment(destination, igpOverride.getDefaultGasUsage()) + ); } function test_quoteGasPayment_gasLimitOverride() public enrollRouters { @@ -241,14 +279,36 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas ); } + function test_quoteGasPaymentOverride_gasLimitOverride(uint256 _gasPriceOverride) public enrollRouters { + vm.assume(_gasPriceOverride < type(uint16).max); + + // arrange + igpOverride.setGasPrice(_gasPriceOverride); + bytes memory messageBody = InterchainCreate2FactoryMessage.encode( + address(1), TypeCasts.addressToBytes32(address(0)), "", new bytes(0), new bytes(0) + ); + + bytes memory hookMetadata = StandardHookMetadata.overrideGasLimit(GAS_LIMIT_OVERRIDE); + + // assert + assertEq( + originRouter.quoteGasPaymentWithOverrides(destination, destinationRouterB32, address(igpOverride), messageBody, hookMetadata), + igpOverride.quoteGasPayment(destination, GAS_LIMIT_OVERRIDE) + ); + } + function assertContractDeployed(address _sender, bytes32 _salt, bytes memory _bytecode, address _ism) private { - address expectedAddress = destinationRouter.deployedAddress(_sender, _salt, _bytecode); + assertContractDeployedOverrides(destinationRouter, _sender, _salt, _bytecode, _ism); + } + + function assertContractDeployedOverrides(InterchainCreate2FactoryRouter _router, address _sender, bytes32 _salt, bytes memory _bytecode, address _ism) private { + address expectedAddress = _router.deployedAddress(_sender, _salt, _bytecode); assertFalse(Address.isContract(expectedAddress)); vm.expectCall(address(_ism), abi.encodeWithSelector(TestIsm.verify.selector)); - vm.expectEmit(true, true, true, true, address(destinationRouter)); + vm.expectEmit(true, true, true, true, address(_router)); emit Deployed(keccak256(_bytecode), keccak256(abi.encode(_sender, _salt)), expectedAddress); environment.processNextPendingMessage(); @@ -292,10 +352,14 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas SomeContract(expectedAddress).someFunction(); } - function assertIgpPayment(uint256 balanceBefore, uint256 balanceAfter, uint256 gasLimit) private view { - uint256 expectedGasPayment = gasLimit * igp.gasPrice(); - assertEq(balanceBefore - balanceAfter, expectedGasPayment); - assertEq(address(igp).balance, expectedGasPayment); + function assertIgpPayment(uint256 _balanceBefore, uint256 _balanceAfter, uint256 _gasLimit) private view { + assertIgpPaymentOverrides(igp, _balanceBefore, _balanceAfter, _gasLimit); + } + + function assertIgpPaymentOverrides(TestInterchainGasPaymaster _igp, uint256 _balanceBefore, uint256 _balanceAfter, uint256 _gasLimit) private view { + uint256 expectedGasPayment = _gasLimit * _igp.gasPrice(); + assertEq(_balanceBefore - _balanceAfter, expectedGasPayment); + assertEq(address(_igp).balance, expectedGasPayment); } function assumeSender(address _sender) internal view { @@ -617,4 +681,27 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas } // TODO - add tests for deployContractWithOverrides + function testFuzz_deployContractOverrides(address sender, bytes32 salt, uint256 _gasPriceOverride) public enrollRouters { + assumeSender(sender); + vm.assume(_gasPriceOverride < type(uint16).max); + + igpOverride.setGasPrice(_gasPriceOverride); + gasPaymentQuote = igpOverride.quoteGasPayment(destination, igpOverride.getDefaultGasUsage()); + + // arrange + vm.deal(sender, gasPaymentQuote); + + uint256 balanceBefore = address(sender).balance; + + // act + bytes memory bytecode = type(SomeContract).creationCode; + vm.prank(sender); + originRouter.deployContractWithOverrides{ value: gasPaymentQuote }(destination, destinationRouterOverrideB32, "", salt, address(igpOverride), bytecode, new bytes(0), new bytes(0)); + + // assert + uint256 balanceAfter = address(sender).balance; + address _ism = address(environment.mailboxes(destination).defaultIsm()); + assertContractDeployedOverrides(destinationRouterOverride, sender, salt, type(SomeContract).creationCode, _ism); + assertIgpPaymentOverrides(igpOverride, balanceBefore, balanceAfter, igpOverride.getDefaultGasUsage()); + } } From 6f9ce6f7dfc5fb79d25cfb3f6f28f478e1f4ccd9 Mon Sep 17 00:00:00 2001 From: Lisandro Corbalan Date: Fri, 13 Sep 2024 17:56:08 -0300 Subject: [PATCH 21/21] Lint --- src/InterchainCreate2FactoryRouter.sol | 7 +-- test/InterchainCreate2FactoryRouter.t.sol | 53 ++++++++++++++++++----- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/InterchainCreate2FactoryRouter.sol b/src/InterchainCreate2FactoryRouter.sol index 5045bcb..d6bfdc4 100644 --- a/src/InterchainCreate2FactoryRouter.sol +++ b/src/InterchainCreate2FactoryRouter.sol @@ -145,11 +145,7 @@ contract InterchainCreate2FactoryRouter is Router { * @dev Does not need to be onlyRemoteRouter, as this application is designed * to receive messages from untrusted remote contracts. */ - function handle( - uint32, - bytes32, - bytes calldata _message - ) external payable override onlyMailbox { + function handle(uint32, bytes32, bytes calldata _message) external payable override onlyMailbox { (bytes32 _sender,, bytes32 _salt, bytes memory _bytecode, bytes memory _initCode) = InterchainCreate2FactoryMessage.decode(_message); @@ -294,7 +290,6 @@ contract InterchainCreate2FactoryRouter is Router { assert(false); } - /** * @notice Dispatches an InterchainCreate2FactoryMessage to the remote router * @param _destination The remote domain diff --git a/test/InterchainCreate2FactoryRouter.t.sol b/test/InterchainCreate2FactoryRouter.t.sol index c964477..4edb502 100644 --- a/test/InterchainCreate2FactoryRouter.t.sol +++ b/test/InterchainCreate2FactoryRouter.t.sol @@ -51,10 +51,7 @@ contract TestInterchainGasPaymaster is InterchainGasPaymaster { initialize(msg.sender, msg.sender); } - function quoteGasPayment( - uint32, - uint256 gasAmount - ) public view override returns (uint256) { + function quoteGasPayment(uint32, uint256 gasAmount) public view override returns (uint256) { return gasPrice * gasAmount; } @@ -259,7 +256,9 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // assert assertEq( - originRouter.quoteGasPaymentWithOverrides(destination, destinationRouterB32, address(igpOverride), messageBody, new bytes(0)), + originRouter.quoteGasPaymentWithOverrides( + destination, destinationRouterB32, address(igpOverride), messageBody, new bytes(0) + ), igpOverride.quoteGasPayment(destination, igpOverride.getDefaultGasUsage()) ); } @@ -292,7 +291,9 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // assert assertEq( - originRouter.quoteGasPaymentWithOverrides(destination, destinationRouterB32, address(igpOverride), messageBody, hookMetadata), + originRouter.quoteGasPaymentWithOverrides( + destination, destinationRouterB32, address(igpOverride), messageBody, hookMetadata + ), igpOverride.quoteGasPayment(destination, GAS_LIMIT_OVERRIDE) ); } @@ -301,7 +302,15 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertContractDeployedOverrides(destinationRouter, _sender, _salt, _bytecode, _ism); } - function assertContractDeployedOverrides(InterchainCreate2FactoryRouter _router, address _sender, bytes32 _salt, bytes memory _bytecode, address _ism) private { + function assertContractDeployedOverrides( + InterchainCreate2FactoryRouter _router, + address _sender, + bytes32 _salt, + bytes memory _bytecode, + address _ism + ) + private + { address expectedAddress = _router.deployedAddress(_sender, _salt, _bytecode); assertFalse(Address.isContract(expectedAddress)); @@ -356,7 +365,15 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas assertIgpPaymentOverrides(igp, _balanceBefore, _balanceAfter, _gasLimit); } - function assertIgpPaymentOverrides(TestInterchainGasPaymaster _igp, uint256 _balanceBefore, uint256 _balanceAfter, uint256 _gasLimit) private view { + function assertIgpPaymentOverrides( + TestInterchainGasPaymaster _igp, + uint256 _balanceBefore, + uint256 _balanceAfter, + uint256 _gasLimit + ) + private + view + { uint256 expectedGasPayment = _gasLimit * _igp.gasPrice(); assertEq(_balanceBefore - _balanceAfter, expectedGasPayment); assertEq(address(_igp).balance, expectedGasPayment); @@ -681,7 +698,14 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas } // TODO - add tests for deployContractWithOverrides - function testFuzz_deployContractOverrides(address sender, bytes32 salt, uint256 _gasPriceOverride) public enrollRouters { + function testFuzz_deployContractOverrides( + address sender, + bytes32 salt, + uint256 _gasPriceOverride + ) + public + enrollRouters + { assumeSender(sender); vm.assume(_gasPriceOverride < type(uint16).max); @@ -696,7 +720,16 @@ contract InterchainCreate2FactoryRouterTest is InterchainCreate2FactoryRouterBas // act bytes memory bytecode = type(SomeContract).creationCode; vm.prank(sender); - originRouter.deployContractWithOverrides{ value: gasPaymentQuote }(destination, destinationRouterOverrideB32, "", salt, address(igpOverride), bytecode, new bytes(0), new bytes(0)); + originRouter.deployContractWithOverrides{ value: gasPaymentQuote }( + destination, + destinationRouterOverrideB32, + "", + salt, + address(igpOverride), + bytecode, + new bytes(0), + new bytes(0) + ); // assert uint256 balanceAfter = address(sender).balance;