diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 85dfe411d..3fb7897d3 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -170,13 +170,10 @@ jobs: #- name: gas # run: yarn workspace @hyperlane-xyz/core run gas-ci - - name: Core unit tests + - name: Unit tests run: yarn workspace @hyperlane-xyz/core run test - - name: Token unit tests - run: yarn workspace @hyperlane-xyz/hyperlane-token run test - - - name: Run Slither + - name: Static analysis uses: crytic/slither-action@v0.3.0 id: slither with: diff --git a/.gitmodules b/.gitmodules index a8fce5500..3077b9e20 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "solidity/lib/forge-std"] path = solidity/lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "typescript/token/lib/forge-std"] - path = typescript/token/lib/forge-std - url = https://github.com/foundry-rs/forge-std diff --git a/Dockerfile b/Dockerfile index a6d4a76bf..860165f92 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,6 @@ COPY .yarn/releases ./.yarn/releases COPY typescript/utils/package.json ./typescript/utils/ COPY typescript/sdk/package.json ./typescript/sdk/ COPY typescript/helloworld/package.json ./typescript/helloworld/ -COPY typescript/token/package.json ./typescript/token/ COPY typescript/infra/package.json ./typescript/infra/ COPY solidity/package.json ./solidity/ diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..1e482524f --- /dev/null +++ b/codecov.yml @@ -0,0 +1,31 @@ +comment: + layout: "header, diff, flags, components" # show component info in the PR comment + +component_management: + default_rules: # default rules that will be inherited by all components + statuses: + - type: project # in this case every component that doens't have a status defined will have a project type one + target: auto + branches: + - "!main" + individual_components: + - component_id: module_core + name: core + paths: + - solidity/contracts/Mailbox.sol + - component_id: module_hooks + name: hooks + paths: + - solidity/contracts/hooks/** + - component_id: module_isms + name: isms + paths: + - solidity/contracts/isms/** + - component_id: module_token + name: token + paths: + - solidity/contracts/token/** + - component_id: module_middlewares + name: middlewares + paths: + - solidity/contracts/middleware/** diff --git a/solidity/.solcover.js b/solidity/.solcover.js index 457648e43..011076d5a 100644 --- a/solidity/.solcover.js +++ b/solidity/.solcover.js @@ -1,5 +1,5 @@ module.exports = { - skipFiles: ['test', 'mock'], + skipFiles: ['test', 'mock', 'upgrade', 'interfaces'], istanbulReporter: ['lcov'], mocha: { enableTimeouts: false, diff --git a/solidity/contracts/Mailbox.sol b/solidity/contracts/Mailbox.sol index abb6c88e0..6cfec22af 100644 --- a/solidity/contracts/Mailbox.sol +++ b/solidity/contracts/Mailbox.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.0; // ============ Internal Imports ============ import {Versioned} from "./upgrade/Versioned.sol"; -import {Indexed} from "./Indexed.sol"; +import {Indexed} from "./libs/Indexed.sol"; import {Message} from "./libs/Message.sol"; import {TypeCasts} from "./libs/TypeCasts.sol"; import {IInterchainSecurityModule, ISpecifiesInterchainSecurityModule} from "./interfaces/IInterchainSecurityModule.sol"; diff --git a/solidity/contracts/GasRouter.sol b/solidity/contracts/client/GasRouter.sol similarity index 93% rename from solidity/contracts/GasRouter.sol rename to solidity/contracts/client/GasRouter.sol index 354a4c6ce..d478aa0c7 100644 --- a/solidity/contracts/GasRouter.sol +++ b/solidity/contracts/client/GasRouter.sol @@ -2,7 +2,7 @@ pragma solidity >=0.6.11; import {Router} from "./Router.sol"; -import {StandardHookMetadata} from "./libs/hooks/StandardHookMetadata.sol"; +import {StandardHookMetadata} from "../hooks/libs/StandardHookMetadata.sol"; abstract contract GasRouter is Router { // ============ Mutable Storage ============ @@ -13,6 +13,8 @@ abstract contract GasRouter is Router { uint256 gas; } + constructor(address _mailbox) Router(_mailbox) {} + /** * @notice Sets the gas amount dispatched for each configured domain. * @param gasConfigs The array of GasRouterConfig structs diff --git a/solidity/contracts/client/MailboxClient.sol b/solidity/contracts/client/MailboxClient.sol index 031df8a65..8d953a971 100644 --- a/solidity/contracts/client/MailboxClient.sol +++ b/solidity/contracts/client/MailboxClient.sol @@ -98,19 +98,23 @@ abstract contract MailboxClient is OwnableUpgradeable { return ""; } - function _msgValue( - uint32 /*_destinationDomain*/ - ) internal view virtual returns (uint256) { - return msg.value; + function _dispatch( + uint32 _destinationDomain, + bytes32 _recipient, + bytes memory _messageBody + ) internal virtual returns (bytes32) { + return + _dispatch(_destinationDomain, _recipient, msg.value, _messageBody); } function _dispatch( uint32 _destinationDomain, bytes32 _recipient, + uint256 _value, bytes memory _messageBody ) internal virtual returns (bytes32) { return - mailbox.dispatch{value: _msgValue(_destinationDomain)}( + mailbox.dispatch{value: _value}( _destinationDomain, _recipient, _messageBody, diff --git a/solidity/contracts/Router.sol b/solidity/contracts/client/Router.sol similarity index 85% rename from solidity/contracts/Router.sol rename to solidity/contracts/client/Router.sol index 634a80e38..e119a7e9f 100644 --- a/solidity/contracts/Router.sol +++ b/solidity/contracts/client/Router.sol @@ -2,12 +2,12 @@ pragma solidity >=0.6.11; // ============ Internal Imports ============ -import {IMessageRecipient} from "./interfaces/IMessageRecipient.sol"; -import {IPostDispatchHook} from "./interfaces/hooks/IPostDispatchHook.sol"; -import {IInterchainSecurityModule} from "./interfaces/IInterchainSecurityModule.sol"; -import {EnumerableMapExtended} from "./libs/EnumerableMapExtended.sol"; -import {MailboxClient} from "./client/MailboxClient.sol"; -import {StandardHookMetadata} from "./libs/hooks/StandardHookMetadata.sol"; +import {IMessageRecipient} from "../interfaces/IMessageRecipient.sol"; +import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; +import {IInterchainSecurityModule} from "../interfaces/IInterchainSecurityModule.sol"; +import {MailboxClient} from "./MailboxClient.sol"; +import {EnumerableMapExtended} from "../libs/EnumerableMapExtended.sol"; +import {StandardHookMetadata} from "../hooks/libs/StandardHookMetadata.sol"; // ============ External Imports ============ import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; @@ -131,7 +131,7 @@ abstract contract Router is MailboxClient, IMessageRecipient { require( contained, string.concat( - "No router enrolled for domain", + "No router enrolled for domain: ", Strings.toString(_domain) ) ); @@ -143,8 +143,17 @@ abstract contract Router is MailboxClient, IMessageRecipient { virtual returns (bytes32) { + return _dispatch(_destinationDomain, msg.value, _messageBody); + } + + function _dispatch( + uint32 _destinationDomain, + uint256 _value, + bytes memory _messageBody + ) internal virtual returns (bytes32) { bytes32 _router = _mustHaveRemoteRouter(_destinationDomain); - return super._dispatch(_destinationDomain, _router, _messageBody); + return + super._dispatch(_destinationDomain, _router, _value, _messageBody); } function _quoteDispatch( diff --git a/solidity/contracts/hooks/MerkleTreeHook.sol b/solidity/contracts/hooks/MerkleTreeHook.sol index 187bb3733..e54ae61d2 100644 --- a/solidity/contracts/hooks/MerkleTreeHook.sol +++ b/solidity/contracts/hooks/MerkleTreeHook.sol @@ -16,9 +16,9 @@ pragma solidity >=0.8.0; import {MerkleLib} from "../libs/Merkle.sol"; import {Message} from "../libs/Message.sol"; import {MailboxClient} from "../client/MailboxClient.sol"; -import {Indexed} from "../Indexed.sol"; -import {AbstractPostDispatchHook} from "./AbstractPostDispatchHook.sol"; -import {StandardHookMetadata} from "../libs/hooks/StandardHookMetadata.sol"; +import {Indexed} from "../libs/Indexed.sol"; +import {AbstractPostDispatchHook} from "./libs/AbstractPostDispatchHook.sol"; +import {StandardHookMetadata} from "./libs/StandardHookMetadata.sol"; contract MerkleTreeHook is AbstractPostDispatchHook, MailboxClient, Indexed { using Message for bytes; diff --git a/solidity/contracts/hooks/OPStackHook.sol b/solidity/contracts/hooks/OPStackHook.sol index d96f471ca..7152a7c84 100644 --- a/solidity/contracts/hooks/OPStackHook.sol +++ b/solidity/contracts/hooks/OPStackHook.sol @@ -14,10 +14,10 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@*/ // ============ Internal Imports ============ -import {AbstractMessageIdAuthHook} from "./AbstractMessageIdAuthHook.sol"; +import {AbstractMessageIdAuthHook} from "./libs/AbstractMessageIdAuthHook.sol"; +import {StandardHookMetadata} from "./libs/StandardHookMetadata.sol"; import {TypeCasts} from "../libs/TypeCasts.sol"; import {Message} from "../libs/Message.sol"; -import {StandardHookMetadata} from "../libs/hooks/StandardHookMetadata.sol"; import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; // ============ External Imports ============ diff --git a/solidity/contracts/hooks/PausableHook.sol b/solidity/contracts/hooks/PausableHook.sol index 33133726e..fe42df4ff 100644 --- a/solidity/contracts/hooks/PausableHook.sol +++ b/solidity/contracts/hooks/PausableHook.sol @@ -13,8 +13,8 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@*/ -import {StandardHookMetadata} from "../libs/hooks/StandardHookMetadata.sol"; -import {AbstractPostDispatchHook} from "./AbstractPostDispatchHook.sol"; +import {StandardHookMetadata} from "../hooks/libs/StandardHookMetadata.sol"; +import {AbstractPostDispatchHook} from "./libs/AbstractPostDispatchHook.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; diff --git a/solidity/contracts/hooks/StaticProtocolFee.sol b/solidity/contracts/hooks/StaticProtocolFee.sol index 1e363cc5e..d41690d93 100644 --- a/solidity/contracts/hooks/StaticProtocolFee.sol +++ b/solidity/contracts/hooks/StaticProtocolFee.sol @@ -15,8 +15,9 @@ pragma solidity >=0.8.0; // ============ Internal Imports ============ import {Message} from "../libs/Message.sol"; -import {StandardHookMetadata} from "../libs/hooks/StandardHookMetadata.sol"; -import {AbstractPostDispatchHook} from "./AbstractPostDispatchHook.sol"; +import {StandardHookMetadata} from "./libs/StandardHookMetadata.sol"; +import {AbstractPostDispatchHook} from "./libs/AbstractPostDispatchHook.sol"; + // ============ External Imports ============ import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/solidity/contracts/hooks/ERC5164Hook.sol b/solidity/contracts/hooks/aggregation/ERC5164Hook.sol similarity index 84% rename from solidity/contracts/hooks/ERC5164Hook.sol rename to solidity/contracts/hooks/aggregation/ERC5164Hook.sol index b98e67b80..17edab835 100644 --- a/solidity/contracts/hooks/ERC5164Hook.sol +++ b/solidity/contracts/hooks/aggregation/ERC5164Hook.sol @@ -14,10 +14,10 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@*/ // ============ Internal Imports ============ -import {TypeCasts} from "../libs/TypeCasts.sol"; -import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; -import {IMessageDispatcher} from "../interfaces/hooks/IMessageDispatcher.sol"; -import {AbstractMessageIdAuthHook} from "./AbstractMessageIdAuthHook.sol"; +import {TypeCasts} from "../../libs/TypeCasts.sol"; +import {IPostDispatchHook} from "../../interfaces/hooks/IPostDispatchHook.sol"; +import {IMessageDispatcher} from "../../interfaces/hooks/IMessageDispatcher.sol"; +import {AbstractMessageIdAuthHook} from "../libs/AbstractMessageIdAuthHook.sol"; // ============ External Imports ============ import {Address} from "@openzeppelin/contracts/utils/Address.sol"; diff --git a/solidity/contracts/hooks/aggregation/StaticAggregationHook.sol b/solidity/contracts/hooks/aggregation/StaticAggregationHook.sol index 683834b91..67e68a13f 100644 --- a/solidity/contracts/hooks/aggregation/StaticAggregationHook.sol +++ b/solidity/contracts/hooks/aggregation/StaticAggregationHook.sol @@ -13,9 +13,9 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@*/ -import {StandardHookMetadata} from "../../libs/hooks/StandardHookMetadata.sol"; +import {StandardHookMetadata} from "../libs/StandardHookMetadata.sol"; +import {AbstractPostDispatchHook} from "../libs/AbstractPostDispatchHook.sol"; import {IPostDispatchHook} from "../../interfaces/hooks/IPostDispatchHook.sol"; -import {AbstractPostDispatchHook} from "../AbstractPostDispatchHook.sol"; import {MetaProxy} from "../../libs/MetaProxy.sol"; contract StaticAggregationHook is AbstractPostDispatchHook { diff --git a/solidity/contracts/igps/InterchainGasPaymaster.sol b/solidity/contracts/hooks/igp/InterchainGasPaymaster.sol similarity index 94% rename from solidity/contracts/igps/InterchainGasPaymaster.sol rename to solidity/contracts/hooks/igp/InterchainGasPaymaster.sol index e401b2158..512f36663 100644 --- a/solidity/contracts/igps/InterchainGasPaymaster.sol +++ b/solidity/contracts/hooks/igp/InterchainGasPaymaster.sol @@ -14,14 +14,13 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@*/ // ============ Internal Imports ============ -import {Message} from "../libs/Message.sol"; -import {StandardHookMetadata} from "../libs/hooks/StandardHookMetadata.sol"; -import {StandardHookMetadata} from "../libs/hooks/StandardHookMetadata.sol"; -import {IGasOracle} from "../interfaces/IGasOracle.sol"; -import {IInterchainGasPaymaster} from "../interfaces/IInterchainGasPaymaster.sol"; -import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; -import {AbstractPostDispatchHook} from "../hooks/AbstractPostDispatchHook.sol"; -import {Indexed} from "../Indexed.sol"; +import {Message} from "../../libs/Message.sol"; +import {StandardHookMetadata} from "../libs/StandardHookMetadata.sol"; +import {IGasOracle} from "../../interfaces/IGasOracle.sol"; +import {IInterchainGasPaymaster} from "../../interfaces/IInterchainGasPaymaster.sol"; +import {IPostDispatchHook} from "../../interfaces/hooks/IPostDispatchHook.sol"; +import {AbstractPostDispatchHook} from "../libs/AbstractPostDispatchHook.sol"; +import {Indexed} from "../../libs/Indexed.sol"; // ============ External Imports ============ import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; @@ -153,6 +152,7 @@ contract InterchainGasPaymaster is ); uint256 _overpayment = msg.value - _requiredPayment; if (_overpayment > 0) { + require(_refundAddress != address(0), "no refund address"); payable(_refundAddress).sendValue(_overpayment); } diff --git a/solidity/contracts/igps/OverheadIgp.sol b/solidity/contracts/hooks/igp/OverheadIgp.sol similarity index 98% rename from solidity/contracts/igps/OverheadIgp.sol rename to solidity/contracts/hooks/igp/OverheadIgp.sol index 279490a01..a7268013e 100644 --- a/solidity/contracts/igps/OverheadIgp.sol +++ b/solidity/contracts/hooks/igp/OverheadIgp.sol @@ -2,7 +2,8 @@ pragma solidity >=0.8.0; // ============ Internal Imports ============ -import {IInterchainGasPaymaster} from "../interfaces/IInterchainGasPaymaster.sol"; +import {IInterchainGasPaymaster} from "../../interfaces/IInterchainGasPaymaster.sol"; + // ============ External Imports ============ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/solidity/contracts/igps/gas-oracles/StorageGasOracle.sol b/solidity/contracts/hooks/igp/StorageGasOracle.sol similarity index 99% rename from solidity/contracts/igps/gas-oracles/StorageGasOracle.sol rename to solidity/contracts/hooks/igp/StorageGasOracle.sol index 7c9173426..1b5507e2e 100644 --- a/solidity/contracts/igps/gas-oracles/StorageGasOracle.sol +++ b/solidity/contracts/hooks/igp/StorageGasOracle.sol @@ -3,6 +3,7 @@ pragma solidity >=0.8.0; // ============ Internal Imports ============ import {IGasOracle} from "../../interfaces/IGasOracle.sol"; + // ============ External Imports ============ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/solidity/contracts/hooks/AbstractMessageIdAuthHook.sol b/solidity/contracts/hooks/libs/AbstractMessageIdAuthHook.sol similarity index 84% rename from solidity/contracts/hooks/AbstractMessageIdAuthHook.sol rename to solidity/contracts/hooks/libs/AbstractMessageIdAuthHook.sol index 6c6f703e2..1fad507f7 100644 --- a/solidity/contracts/hooks/AbstractMessageIdAuthHook.sol +++ b/solidity/contracts/hooks/libs/AbstractMessageIdAuthHook.sol @@ -14,13 +14,12 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@*/ // ============ Internal Imports ============ -import {AbstractMessageIdAuthorizedIsm} from "../isms/hook/AbstractMessageIdAuthorizedIsm.sol"; import {AbstractPostDispatchHook} from "./AbstractPostDispatchHook.sol"; -import {TypeCasts} from "../libs/TypeCasts.sol"; -import {Message} from "../libs/Message.sol"; -import {StandardHookMetadata} from "../libs/hooks/StandardHookMetadata.sol"; -import {MailboxClient} from "../client/MailboxClient.sol"; -import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; +import {AbstractMessageIdAuthorizedIsm} from "../../isms/hook/AbstractMessageIdAuthorizedIsm.sol"; +import {TypeCasts} from "../../libs/TypeCasts.sol"; +import {Message} from "../../libs/Message.sol"; +import {StandardHookMetadata} from "./StandardHookMetadata.sol"; +import {MailboxClient} from "../../client/MailboxClient.sol"; /** * @title AbstractMessageIdAuthHook @@ -44,10 +43,10 @@ abstract contract AbstractMessageIdAuthHook is // ============ Constructor ============ constructor( - address mailbox, + address _mailbox, uint32 _destinationDomain, address _ism - ) MailboxClient(mailbox) { + ) MailboxClient(_mailbox) { require(_ism != address(0), "AbstractMessageIdAuthHook: invalid ISM"); require( _destinationDomain != 0, diff --git a/solidity/contracts/hooks/AbstractPostDispatchHook.sol b/solidity/contracts/hooks/libs/AbstractPostDispatchHook.sol similarity index 94% rename from solidity/contracts/hooks/AbstractPostDispatchHook.sol rename to solidity/contracts/hooks/libs/AbstractPostDispatchHook.sol index 58b057472..19f430045 100644 --- a/solidity/contracts/hooks/AbstractPostDispatchHook.sol +++ b/solidity/contracts/hooks/libs/AbstractPostDispatchHook.sol @@ -14,8 +14,8 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@*/ // ============ Internal Imports ============ -import {StandardHookMetadata} from "../libs/hooks/StandardHookMetadata.sol"; -import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; +import {StandardHookMetadata} from "./StandardHookMetadata.sol"; +import {IPostDispatchHook} from "../../interfaces/hooks/IPostDispatchHook.sol"; /** * @title AbstractPostDispatch diff --git a/solidity/contracts/libs/hooks/StandardHookMetadata.sol b/solidity/contracts/hooks/libs/StandardHookMetadata.sol similarity index 100% rename from solidity/contracts/libs/hooks/StandardHookMetadata.sol rename to solidity/contracts/hooks/libs/StandardHookMetadata.sol diff --git a/solidity/contracts/hooks/DestinationRecipientRoutingHook.sol b/solidity/contracts/hooks/routing/DestinationRecipientRoutingHook.sol similarity index 92% rename from solidity/contracts/hooks/DestinationRecipientRoutingHook.sol rename to solidity/contracts/hooks/routing/DestinationRecipientRoutingHook.sol index e930357cd..147a12934 100644 --- a/solidity/contracts/hooks/DestinationRecipientRoutingHook.sol +++ b/solidity/contracts/hooks/routing/DestinationRecipientRoutingHook.sol @@ -13,8 +13,8 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@*/ -import {Message} from "../libs/Message.sol"; -import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; +import {Message} from "../../libs/Message.sol"; +import {IPostDispatchHook} from "../../interfaces/hooks/IPostDispatchHook.sol"; import {DomainRoutingHook} from "./DomainRoutingHook.sol"; contract DestinationRecipientRoutingHook is DomainRoutingHook { diff --git a/solidity/contracts/hooks/DomainRoutingHook.sol b/solidity/contracts/hooks/routing/DomainRoutingHook.sol similarity index 88% rename from solidity/contracts/hooks/DomainRoutingHook.sol rename to solidity/contracts/hooks/routing/DomainRoutingHook.sol index af5588583..4b07703b4 100644 --- a/solidity/contracts/hooks/DomainRoutingHook.sol +++ b/solidity/contracts/hooks/routing/DomainRoutingHook.sol @@ -14,11 +14,11 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@*/ // ============ Internal Imports ============ -import {Message} from "../libs/Message.sol"; -import {StandardHookMetadata} from "../libs/hooks/StandardHookMetadata.sol"; -import {MailboxClient} from "../client/MailboxClient.sol"; -import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; -import {AbstractPostDispatchHook} from "./AbstractPostDispatchHook.sol"; +import {StandardHookMetadata} from "../libs/StandardHookMetadata.sol"; +import {AbstractPostDispatchHook} from "../libs/AbstractPostDispatchHook.sol"; +import {MailboxClient} from "../../client/MailboxClient.sol"; +import {Message} from "../../libs/Message.sol"; +import {IPostDispatchHook} from "../../interfaces/hooks/IPostDispatchHook.sol"; // ============ External Imports ============ import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; diff --git a/solidity/contracts/hooks/FallbackDomainRoutingHook.sol b/solidity/contracts/hooks/routing/FallbackDomainRoutingHook.sol similarity index 87% rename from solidity/contracts/hooks/FallbackDomainRoutingHook.sol rename to solidity/contracts/hooks/routing/FallbackDomainRoutingHook.sol index 2aeee28b8..4d9fc70d4 100644 --- a/solidity/contracts/hooks/FallbackDomainRoutingHook.sol +++ b/solidity/contracts/hooks/routing/FallbackDomainRoutingHook.sol @@ -13,10 +13,10 @@ pragma solidity >=0.8.0; @@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @@@@@@@@*/ -import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; -import {IMailbox} from "../interfaces/IMailbox.sol"; +import {IPostDispatchHook} from "../../interfaces/hooks/IPostDispatchHook.sol"; +import {IMailbox} from "../../interfaces/IMailbox.sol"; import {DomainRoutingHook} from "./DomainRoutingHook.sol"; -import {Message} from "../libs/Message.sol"; +import {Message} from "../../libs/Message.sol"; /** * @title FallbackDomainRoutingHook diff --git a/solidity/contracts/interfaces/IValidatorAnnounce.sol b/solidity/contracts/interfaces/IValidatorAnnounce.sol index ef7c6c3d3..27a57e676 100644 --- a/solidity/contracts/interfaces/IValidatorAnnounce.sol +++ b/solidity/contracts/interfaces/IValidatorAnnounce.sol @@ -2,12 +2,6 @@ pragma solidity >=0.6.11; interface IValidatorAnnounce { - /// @notice Returns the local domain for validator announcements - function localDomain() external view returns (uint32); - - /// @notice Returns the mailbox contract for validator announcements - function mailbox() external view returns (address); - /// @notice Returns a list of validators that have made announcements function getAnnouncedValidators() external view returns (address[] memory); diff --git a/solidity/contracts/interfaces/middleware/IInterchainAccountRouter.sol b/solidity/contracts/interfaces/middleware/IInterchainAccountRouter.sol deleted file mode 100644 index c39f37bf8..000000000 --- a/solidity/contracts/interfaces/middleware/IInterchainAccountRouter.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.6.11; - -import {OwnableMulticall} from "../../OwnableMulticall.sol"; -import {CallLib} from "../../libs/Call.sol"; - -interface IInterchainAccountRouter { - function callRemote( - uint32 _destination, - address _to, - uint256 _value, - bytes calldata _data - ) external returns (bytes32); - - function callRemote(uint32 _destination, CallLib.Call[] calldata calls) - external - returns (bytes32); - - function callRemoteWithOverrides( - uint32 _destination, - bytes32 _router, - bytes32 _ism, - CallLib.Call[] calldata calls - ) external returns (bytes32); - - function getLocalInterchainAccount( - uint32 _origin, - bytes32 _router, - bytes32 _owner, - address _ism - ) external view returns (OwnableMulticall); - - function getLocalInterchainAccount( - uint32 _origin, - address _router, - address _owner, - address _ism - ) external view returns (OwnableMulticall); - - function getRemoteInterchainAccount( - address _router, - address _owner, - address _ism - ) external view returns (address); - - function getRemoteInterchainAccount(uint32 _destination, address _owner) - external - view - returns (address); -} diff --git a/solidity/contracts/interfaces/middleware/IInterchainQueryRouter.sol b/solidity/contracts/interfaces/middleware/IInterchainQueryRouter.sol deleted file mode 100644 index 83df9c50e..000000000 --- a/solidity/contracts/interfaces/middleware/IInterchainQueryRouter.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.6.11; - -import {CallLib} from "../../libs/Call.sol"; - -interface IInterchainQueryRouter { - function query( - uint32 _destination, - address _to, - bytes memory _data, - bytes memory _callback - ) external returns (bytes32); - - function query( - uint32 _destination, - CallLib.StaticCallWithCallback[] calldata calls - ) external returns (bytes32); -} diff --git a/solidity/contracts/isms/aggregation/AbstractAggregationIsm.sol b/solidity/contracts/isms/aggregation/AbstractAggregationIsm.sol index 4de9b9045..b8297287c 100644 --- a/solidity/contracts/isms/aggregation/AbstractAggregationIsm.sol +++ b/solidity/contracts/isms/aggregation/AbstractAggregationIsm.sol @@ -7,7 +7,7 @@ import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; // ============ Internal Imports ============ import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol"; import {IAggregationIsm} from "../../interfaces/isms/IAggregationIsm.sol"; -import {AggregationIsmMetadata} from "../../libs/isms/AggregationIsmMetadata.sol"; +import {AggregationIsmMetadata} from "../../isms/libs/AggregationIsmMetadata.sol"; /** * @title AggregationIsm diff --git a/solidity/contracts/isms/aggregation/StaticAggregationIsm.sol b/solidity/contracts/isms/aggregation/StaticAggregationIsm.sol index f39d74738..8ba2bb64b 100644 --- a/solidity/contracts/isms/aggregation/StaticAggregationIsm.sol +++ b/solidity/contracts/isms/aggregation/StaticAggregationIsm.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.0; // ============ Internal Imports ============ import {AbstractAggregationIsm} from "./AbstractAggregationIsm.sol"; -import {AggregationIsmMetadata} from "../../libs/isms/AggregationIsmMetadata.sol"; +import {AggregationIsmMetadata} from "../../isms/libs/AggregationIsmMetadata.sol"; import {MetaProxy} from "../../libs/MetaProxy.sol"; /** diff --git a/solidity/contracts/isms/hook/ERC5164ISM.sol b/solidity/contracts/isms/hook/ERC5164Ism.sol similarity index 100% rename from solidity/contracts/isms/hook/ERC5164ISM.sol rename to solidity/contracts/isms/hook/ERC5164Ism.sol diff --git a/solidity/contracts/isms/hook/OPStackIsm.sol b/solidity/contracts/isms/hook/OPStackIsm.sol index 2766414d8..ba60db08b 100644 --- a/solidity/contracts/isms/hook/OPStackIsm.sol +++ b/solidity/contracts/isms/hook/OPStackIsm.sol @@ -19,9 +19,9 @@ import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityMod import {Message} from "../../libs/Message.sol"; import {TypeCasts} from "../../libs/TypeCasts.sol"; import {AbstractMessageIdAuthorizedIsm} from "./AbstractMessageIdAuthorizedIsm.sol"; -import {CrossChainEnabledOptimism} from "./crossChainEnabled/optimism/CrossChainEnabledOptimism.sol"; // ============ External Imports ============ +import {CrossChainEnabledOptimism} from "@openzeppelin/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; /** diff --git a/solidity/contracts/isms/hook/crossChainEnabled/CrossChainEnabled.sol b/solidity/contracts/isms/hook/crossChainEnabled/CrossChainEnabled.sol deleted file mode 100644 index e0a74fea8..000000000 --- a/solidity/contracts/isms/hook/crossChainEnabled/CrossChainEnabled.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.6.0) (crosschain/CrossChainEnabled.sol) - -pragma solidity ^0.8.4; - -import "./errors.sol"; - -/** - * @author OpenZeppelin - * @dev LibOptimism was removed from the OpenZeppelin Contracts library as of v4.7.0 - * @dev Provides information for building cross-chain aware contracts. This - * abstract contract provides accessors and modifiers to control the execution - * flow when receiving cross-chain messages. - * - * Actual implementations of cross-chain aware contracts, which are based on - * this abstraction, will have to inherit from a bridge-specific - * specialization. Such specializations are provided under - * `crosschain//CrossChainEnabled.sol`. - * - * _Available since v4.6._ - */ -abstract contract CrossChainEnabled { - /** - * @dev Throws if the current function call is not the result of a - * cross-chain execution. - */ - modifier onlyCrossChain() { - if (!_isCrossChain()) revert NotCrossChainCall(); - _; - } - - /** - * @dev Throws if the current function call is not the result of a - * cross-chain execution initiated by `account`. - */ - modifier onlyCrossChainSender(address expected) { - address actual = _crossChainSender(); - if (expected != actual) - revert InvalidCrossChainSender(actual, expected); - _; - } - - /** - * @dev Returns whether the current function call is the result of a - * cross-chain message. - */ - function _isCrossChain() internal view virtual returns (bool); - - /** - * @dev Returns the address of the sender of the cross-chain message that - * triggered the current function call. - * - * IMPORTANT: Should revert with `NotCrossChainCall` if the current function - * call is not the result of a cross-chain message. - */ - function _crossChainSender() internal view virtual returns (address); -} diff --git a/solidity/contracts/isms/hook/crossChainEnabled/errors.sol b/solidity/contracts/isms/hook/crossChainEnabled/errors.sol deleted file mode 100644 index 004460e97..000000000 --- a/solidity/contracts/isms/hook/crossChainEnabled/errors.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.6.0) (crosschain/errors.sol) - -pragma solidity ^0.8.4; - -error NotCrossChainCall(); -error InvalidCrossChainSender(address actual, address expected); diff --git a/solidity/contracts/isms/hook/crossChainEnabled/optimism/CrossChainEnabledOptimism.sol b/solidity/contracts/isms/hook/crossChainEnabled/optimism/CrossChainEnabledOptimism.sol deleted file mode 100644 index acb93ffc5..000000000 --- a/solidity/contracts/isms/hook/crossChainEnabled/optimism/CrossChainEnabledOptimism.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/optimism/CrossChainEnabledOptimism.sol) - -pragma solidity ^0.8.4; - -import {CrossChainEnabled} from "../CrossChainEnabled.sol"; -import {LibOptimism} from "./LibOptimism.sol"; - -/** - * @author OpenZeppelin - * @dev CrossChainEnabledOptimism was removed from the OpenZeppelin Contracts library as of v4.7.0 - * @dev https://www.optimism.io/[Optimism] specialization or the - * {CrossChainEnabled} abstraction. - * - * The messenger (`CrossDomainMessenger`) contract is provided and maintained by - * the optimism team. You can find the address of this contract on mainnet and - * kovan in the https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts/deployments[deployments section of Optimism monorepo]. - * - * _Available since v4.6._ - */ -abstract contract CrossChainEnabledOptimism is CrossChainEnabled { - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - address private immutable _messenger; - - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(address messenger) { - _messenger = messenger; - } - - /** - * @dev see {CrossChainEnabled-_isCrossChain} - */ - function _isCrossChain() internal view virtual override returns (bool) { - return LibOptimism.isCrossChain(_messenger); - } - - /** - * @dev see {CrossChainEnabled-_crossChainSender} - */ - function _crossChainSender() - internal - view - virtual - override - onlyCrossChain - returns (address) - { - return LibOptimism.crossChainSender(_messenger); - } -} diff --git a/solidity/contracts/isms/hook/crossChainEnabled/optimism/LibOptimism.sol b/solidity/contracts/isms/hook/crossChainEnabled/optimism/LibOptimism.sol deleted file mode 100644 index 9b71e7b8b..000000000 --- a/solidity/contracts/isms/hook/crossChainEnabled/optimism/LibOptimism.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/optimism/LibOptimism.sol) - -pragma solidity ^0.8.4; - -import {ICrossDomainMessenger} from "../../../../interfaces/optimism/ICrossDomainMessenger.sol"; -import {NotCrossChainCall} from "../errors.sol"; - -/** - * @dev Primitives for cross-chain aware contracts for https://www.optimism.io/[Optimism]. - * See the https://community.optimism.io/docs/developers/bridge/messaging/#accessing-msg-sender[documentation] - * for the functionality used here. - */ -library LibOptimism { - /** - * @dev Returns whether the current function call is the result of a - * cross-chain message relayed by `messenger`. - */ - function isCrossChain(address messenger) internal view returns (bool) { - return msg.sender == messenger; - } - - /** - * @dev Returns the address of the sender that triggered the current - * cross-chain message through `messenger`. - * - * NOTE: {isCrossChain} should be checked before trying to recover the - * sender, as it will revert with `NotCrossChainCall` if the current - * function call is not the result of a cross-chain message. - */ - function crossChainSender(address messenger) - internal - view - returns (address) - { - if (!isCrossChain(messenger)) revert NotCrossChainCall(); - - return ICrossDomainMessenger(messenger).xDomainMessageSender(); - } -} diff --git a/solidity/contracts/libs/isms/AggregationIsmMetadata.sol b/solidity/contracts/isms/libs/AggregationIsmMetadata.sol similarity index 100% rename from solidity/contracts/libs/isms/AggregationIsmMetadata.sol rename to solidity/contracts/isms/libs/AggregationIsmMetadata.sol diff --git a/solidity/contracts/libs/isms/MerkleRootMultisigIsmMetadata.sol b/solidity/contracts/isms/libs/MerkleRootMultisigIsmMetadata.sol similarity index 100% rename from solidity/contracts/libs/isms/MerkleRootMultisigIsmMetadata.sol rename to solidity/contracts/isms/libs/MerkleRootMultisigIsmMetadata.sol diff --git a/solidity/contracts/libs/isms/MessageIdMultisigIsmMetadata.sol b/solidity/contracts/isms/libs/MessageIdMultisigIsmMetadata.sol similarity index 100% rename from solidity/contracts/libs/isms/MessageIdMultisigIsmMetadata.sol rename to solidity/contracts/isms/libs/MessageIdMultisigIsmMetadata.sol diff --git a/solidity/contracts/isms/multisig/AbstractMerkleRootMultisigIsm.sol b/solidity/contracts/isms/multisig/AbstractMerkleRootMultisigIsm.sol index 0e3cfba01..69b34fdba 100644 --- a/solidity/contracts/isms/multisig/AbstractMerkleRootMultisigIsm.sol +++ b/solidity/contracts/isms/multisig/AbstractMerkleRootMultisigIsm.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.0; // ============ Internal Imports ============ import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol"; import {AbstractMultisigIsm} from "./AbstractMultisigIsm.sol"; -import {MerkleRootMultisigIsmMetadata} from "../../libs/isms/MerkleRootMultisigIsmMetadata.sol"; +import {MerkleRootMultisigIsmMetadata} from "../../isms/libs/MerkleRootMultisigIsmMetadata.sol"; import {Message} from "../../libs/Message.sol"; import {MerkleLib} from "../../libs/Merkle.sol"; import {CheckpointLib} from "../../libs/CheckpointLib.sol"; diff --git a/solidity/contracts/isms/multisig/AbstractMessageIdMultisigIsm.sol b/solidity/contracts/isms/multisig/AbstractMessageIdMultisigIsm.sol index 285ff881f..19e10410f 100644 --- a/solidity/contracts/isms/multisig/AbstractMessageIdMultisigIsm.sol +++ b/solidity/contracts/isms/multisig/AbstractMessageIdMultisigIsm.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.0; // ============ Internal Imports ============ import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol"; import {AbstractMultisigIsm} from "./AbstractMultisigIsm.sol"; -import {MessageIdMultisigIsmMetadata} from "../../libs/isms/MessageIdMultisigIsmMetadata.sol"; +import {MessageIdMultisigIsmMetadata} from "../libs/MessageIdMultisigIsmMetadata.sol"; import {Message} from "../../libs/Message.sol"; import {CheckpointLib} from "../../libs/CheckpointLib.sol"; diff --git a/solidity/contracts/ValidatorAnnounce.sol b/solidity/contracts/isms/multisig/ValidatorAnnounce.sol similarity index 72% rename from solidity/contracts/ValidatorAnnounce.sol rename to solidity/contracts/isms/multisig/ValidatorAnnounce.sol index 017afe879..32fc885d2 100644 --- a/solidity/contracts/ValidatorAnnounce.sol +++ b/solidity/contracts/isms/multisig/ValidatorAnnounce.sol @@ -2,10 +2,11 @@ pragma solidity >=0.8.0; // ============ Internal Imports ============ -import {IValidatorAnnounce} from "./interfaces/IValidatorAnnounce.sol"; -import {IMailbox} from "./interfaces/IMailbox.sol"; -import {TypeCasts} from "./libs/TypeCasts.sol"; -import {ValidatorAnnouncements} from "./libs/ValidatorAnnouncements.sol"; +import {IValidatorAnnounce} from "../../interfaces/IValidatorAnnounce.sol"; +import {IMailbox} from "../../interfaces/IMailbox.sol"; +import {TypeCasts} from "../../libs/TypeCasts.sol"; +import {MailboxClient} from "../../client/MailboxClient.sol"; + // ============ External Imports ============ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; @@ -14,19 +15,12 @@ import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; * @title ValidatorAnnounce * @notice Stores the location(s) of validator signed checkpoints */ -contract ValidatorAnnounce is IValidatorAnnounce { +contract ValidatorAnnounce is MailboxClient, IValidatorAnnounce { // ============ Libraries ============ using EnumerableSet for EnumerableSet.AddressSet; using TypeCasts for address; - // ============ Constants ============ - - // Address of the mailbox being validated - address public immutable mailbox; - // Domain of chain on which the contract is deployed - uint32 public immutable localDomain; - // ============ Public Storage ============ // The set of validators that have announced @@ -51,10 +45,7 @@ contract ValidatorAnnounce is IValidatorAnnounce { // ============ Constructor ============ - constructor(address _mailbox) { - mailbox = _mailbox; - localDomain = IMailbox(mailbox).localDomain(); - } + constructor(address _mailbox) MailboxClient(_mailbox) {} // ============ External Functions ============ @@ -79,8 +70,7 @@ contract ValidatorAnnounce is IValidatorAnnounce { replayProtection[_replayId] = true; // Verify that the signature matches the declared validator - bytes32 _announcementDigest = ValidatorAnnouncements - .getAnnouncementDigest(mailbox, localDomain, _storageLocation); + bytes32 _announcementDigest = getAnnouncementDigest(_storageLocation); address _signer = ECDSA.recover(_announcementDigest, _signature); require(_signer == _validator, "!signature"); @@ -114,4 +104,34 @@ contract ValidatorAnnounce is IValidatorAnnounce { function getAnnouncedValidators() external view returns (address[] memory) { return validators.values(); } + + /** + * @notice Returns the digest validators are expected to sign when signing announcements. + * @param _storageLocation Storage location string. + * @return The digest of the announcement. + */ + function getAnnouncementDigest(string memory _storageLocation) + public + view + returns (bytes32) + { + return + ECDSA.toEthSignedMessageHash( + keccak256(abi.encodePacked(_domainHash(), _storageLocation)) + ); + } + + /** + * @notice Returns the domain separator used in validator announcements. + */ + function _domainHash() internal view returns (bytes32) { + return + keccak256( + abi.encodePacked( + localDomain, + address(mailbox).addressToBytes32(), + "HYPERLANE_ANNOUNCEMENT" + ) + ); + } } diff --git a/solidity/contracts/isms/routing/InterchainAccountIsm.sol b/solidity/contracts/isms/routing/InterchainAccountIsm.sol index d22e0b42d..5e61198d9 100644 --- a/solidity/contracts/isms/routing/InterchainAccountIsm.sol +++ b/solidity/contracts/isms/routing/InterchainAccountIsm.sol @@ -5,7 +5,7 @@ import {AbstractRoutingIsm} from "./AbstractRoutingIsm.sol"; import {IMailbox} from "../../interfaces/IMailbox.sol"; import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol"; import {Message} from "../../libs/Message.sol"; -import {InterchainAccountMessage} from "../../libs/middleware/InterchainAccountMessage.sol"; +import {InterchainAccountMessage} from "../../middleware/libs/InterchainAccountMessage.sol"; /** * @title InterchainAccountIsm diff --git a/solidity/contracts/Indexed.sol b/solidity/contracts/libs/Indexed.sol similarity index 100% rename from solidity/contracts/Indexed.sol rename to solidity/contracts/libs/Indexed.sol diff --git a/solidity/contracts/libs/ValidatorAnnouncements.sol b/solidity/contracts/libs/ValidatorAnnouncements.sol deleted file mode 100644 index 461d63249..000000000 --- a/solidity/contracts/libs/ValidatorAnnouncements.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.8.0; -// ============ Internal Imports ============ -import {TypeCasts} from "./TypeCasts.sol"; -// ============ External Imports ============ -import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; - -library ValidatorAnnouncements { - using TypeCasts for address; - - /** - * @notice Returns the digest validators are expected to sign when signing announcements. - * @param _mailbox Address of the mailbox being validated - * @param _localDomain Domain of chain on which the contract is deployed - * @param _storageLocation Storage location string. - * @return The digest of the announcement. - */ - function getAnnouncementDigest( - address _mailbox, - uint32 _localDomain, - string memory _storageLocation - ) internal pure returns (bytes32) { - bytes32 _domainHash = keccak256( - abi.encodePacked( - _localDomain, - _mailbox.addressToBytes32(), - "HYPERLANE_ANNOUNCEMENT" - ) - ); - return - ECDSA.toEthSignedMessageHash( - keccak256(abi.encodePacked(_domainHash, _storageLocation)) - ); - } -} diff --git a/solidity/contracts/middleware/InterchainAccountRouter.sol b/solidity/contracts/middleware/InterchainAccountRouter.sol index 043eca180..60516bf1f 100644 --- a/solidity/contracts/middleware/InterchainAccountRouter.sol +++ b/solidity/contracts/middleware/InterchainAccountRouter.sol @@ -2,15 +2,13 @@ pragma solidity ^0.8.13; // ============ Internal Imports ============ -import {OwnableMulticall} from "../OwnableMulticall.sol"; -import {IRouter} from "../interfaces/IRouter.sol"; -import {IInterchainAccountRouter} from "../interfaces/middleware/IInterchainAccountRouter.sol"; -import {InterchainAccountMessage} from "../libs/middleware/InterchainAccountMessage.sol"; +import {OwnableMulticall} from "./libs/OwnableMulticall.sol"; +import {InterchainAccountMessage} from "./libs/InterchainAccountMessage.sol"; +import {CallLib} from "./libs/Call.sol"; import {MinimalProxy} from "../libs/MinimalProxy.sol"; -import {CallLib} from "../libs/Call.sol"; import {TypeCasts} from "../libs/TypeCasts.sol"; import {EnumerableMapExtended} from "../libs/EnumerableMapExtended.sol"; -import {Router, MailboxClient} from "../Router.sol"; +import {Router} from "../client/Router.sol"; // ============ External Imports ============ import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; @@ -21,7 +19,7 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Ini * @title A contract that allows accounts on chain A to call contracts via a * proxy contract on chain B. */ -contract InterchainAccountRouter is Router, IInterchainAccountRouter { +contract InterchainAccountRouter is Router { // ============ Libraries ============ using TypeCasts for address; diff --git a/solidity/contracts/middleware/InterchainQueryRouter.sol b/solidity/contracts/middleware/InterchainQueryRouter.sol index c983bcda9..4c06f4112 100644 --- a/solidity/contracts/middleware/InterchainQueryRouter.sol +++ b/solidity/contracts/middleware/InterchainQueryRouter.sol @@ -2,10 +2,9 @@ pragma solidity ^0.8.13; // ============ Internal Imports ============ -import {CallLib} from "../libs/Call.sol"; -import {Router} from "../Router.sol"; -import {IInterchainQueryRouter} from "../interfaces/middleware/IInterchainQueryRouter.sol"; -import {InterchainQueryMessage} from "../libs/middleware/InterchainQueryMessage.sol"; +import {Router} from "../client/Router.sol"; +import {CallLib} from "./libs/Call.sol"; +import {InterchainQueryMessage} from "./libs/InterchainQueryMessage.sol"; import {TypeCasts} from "../libs/TypeCasts.sol"; // ============ External Imports ============ @@ -17,7 +16,7 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Ini * @title Interchain Query Router that performs remote view calls on other chains and returns the result. * @dev Currently does not support Sovereign Consensus (user specified Interchain Security Modules). */ -contract InterchainQueryRouter is Router, IInterchainQueryRouter { +contract InterchainQueryRouter is Router { using TypeCasts for address; using TypeCasts for bytes32; using InterchainQueryMessage for bytes; diff --git a/solidity/contracts/libs/Call.sol b/solidity/contracts/middleware/libs/Call.sol similarity index 98% rename from solidity/contracts/libs/Call.sol rename to solidity/contracts/middleware/libs/Call.sol index c090f3cdc..0eaa87937 100644 --- a/solidity/contracts/libs/Call.sol +++ b/solidity/contracts/middleware/libs/Call.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.13; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; -import {TypeCasts} from "./TypeCasts.sol"; +import {TypeCasts} from "../../libs/TypeCasts.sol"; library CallLib { struct StaticCall { diff --git a/solidity/contracts/libs/middleware/InterchainAccountMessage.sol b/solidity/contracts/middleware/libs/InterchainAccountMessage.sol similarity index 97% rename from solidity/contracts/libs/middleware/InterchainAccountMessage.sol rename to solidity/contracts/middleware/libs/InterchainAccountMessage.sol index 9f8baa216..fbc399912 100644 --- a/solidity/contracts/libs/middleware/InterchainAccountMessage.sol +++ b/solidity/contracts/middleware/libs/InterchainAccountMessage.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.8.0; -import {CallLib} from "../Call.sol"; -import {TypeCasts} from "../TypeCasts.sol"; +import {CallLib} from "./Call.sol"; +import {TypeCasts} from "../../libs/TypeCasts.sol"; /** * Format of message: diff --git a/solidity/contracts/libs/middleware/InterchainQueryMessage.sol b/solidity/contracts/middleware/libs/InterchainQueryMessage.sol similarity index 99% rename from solidity/contracts/libs/middleware/InterchainQueryMessage.sol rename to solidity/contracts/middleware/libs/InterchainQueryMessage.sol index 474337f4b..17fabac55 100644 --- a/solidity/contracts/libs/middleware/InterchainQueryMessage.sol +++ b/solidity/contracts/middleware/libs/InterchainQueryMessage.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; -import {CallLib} from "../Call.sol"; +import {CallLib} from "./Call.sol"; /** * Format of message: diff --git a/solidity/contracts/OwnableMulticall.sol b/solidity/contracts/middleware/libs/OwnableMulticall.sol similarity index 94% rename from solidity/contracts/OwnableMulticall.sol rename to solidity/contracts/middleware/libs/OwnableMulticall.sol index 88fb9838b..ad67af036 100644 --- a/solidity/contracts/OwnableMulticall.sol +++ b/solidity/contracts/middleware/libs/OwnableMulticall.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.13; // ============ Internal Imports ============ -import {CallLib} from "./libs/Call.sol"; +import {CallLib} from "./Call.sol"; /* * @title OwnableMulticall diff --git a/solidity/contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol b/solidity/contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol index 95b61aeb7..d92534559 100644 --- a/solidity/contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol +++ b/solidity/contracts/middleware/liquidity-layer/LiquidityLayerRouter.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; -import {Router} from "../../Router.sol"; +import {Router} from "../../client/Router.sol"; import {ILiquidityLayerRouter} from "../../interfaces/ILiquidityLayerRouter.sol"; import {ICircleMessageTransmitter} from "./interfaces/circle/ICircleMessageTransmitter.sol"; diff --git a/solidity/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.sol b/solidity/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.sol index f21cda410..0a7d67d90 100644 --- a/solidity/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.sol +++ b/solidity/contracts/middleware/liquidity-layer/adapters/CircleBridgeAdapter.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; -import {Router} from "../../../Router.sol"; +import {Router} from "../../../client/Router.sol"; import {ITokenMessenger} from "../interfaces/circle/ITokenMessenger.sol"; import {ICircleMessageTransmitter} from "../interfaces/circle/ICircleMessageTransmitter.sol"; diff --git a/solidity/contracts/middleware/liquidity-layer/adapters/PortalAdapter.sol b/solidity/contracts/middleware/liquidity-layer/adapters/PortalAdapter.sol index 734ed202a..4a290af20 100644 --- a/solidity/contracts/middleware/liquidity-layer/adapters/PortalAdapter.sol +++ b/solidity/contracts/middleware/liquidity-layer/adapters/PortalAdapter.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; -import {Router} from "../../../Router.sol"; +import {Router} from "../../../client/Router.sol"; import {IPortalTokenBridge} from "../interfaces/portal/IPortalTokenBridge.sol"; import {ILiquidityLayerAdapter} from "../interfaces/ILiquidityLayerAdapter.sol"; diff --git a/typescript/token/contracts/test/ERC20Test.sol b/solidity/contracts/test/ERC20Test.sol similarity index 100% rename from typescript/token/contracts/test/ERC20Test.sol rename to solidity/contracts/test/ERC20Test.sol diff --git a/typescript/token/contracts/test/ERC721Test.sol b/solidity/contracts/test/ERC721Test.sol similarity index 100% rename from typescript/token/contracts/test/ERC721Test.sol rename to solidity/contracts/test/ERC721Test.sol diff --git a/solidity/contracts/test/TestGasRouter.sol b/solidity/contracts/test/TestGasRouter.sol index a639bf692..095baf33a 100644 --- a/solidity/contracts/test/TestGasRouter.sol +++ b/solidity/contracts/test/TestGasRouter.sol @@ -1,18 +1,18 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.6.11; -import "./TestRouter.sol"; -import "../GasRouter.sol"; +import "../client/GasRouter.sol"; -contract TestGasRouter is TestRouter, GasRouter { - constructor(address _mailbox) TestRouter(_mailbox) {} +contract TestGasRouter is GasRouter { + constructor(address _mailbox) GasRouter(_mailbox) {} - function _metadata(uint32 _destination) - internal - view - override(GasRouter, MailboxClient) - returns (bytes memory) - { - return GasRouter._metadata(_destination); + function dispatch(uint32 _destination, bytes memory _msg) external payable { + _dispatch(_destination, _msg); } + + function _handle( + uint32, + bytes32, + bytes calldata + ) internal pure override {} } diff --git a/solidity/contracts/test/TestInterchainGasPaymaster.sol b/solidity/contracts/test/TestInterchainGasPaymaster.sol index d503f5756..9a75a8f4e 100644 --- a/solidity/contracts/test/TestInterchainGasPaymaster.sol +++ b/solidity/contracts/test/TestInterchainGasPaymaster.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.0; // ============ Internal Imports ============ -import {InterchainGasPaymaster} from "../igps/InterchainGasPaymaster.sol"; +import {InterchainGasPaymaster} from "../hooks/igp/InterchainGasPaymaster.sol"; contract TestInterchainGasPaymaster is InterchainGasPaymaster { uint256 public constant gasPrice = 10; diff --git a/solidity/contracts/test/TestPostDispatchHook.sol b/solidity/contracts/test/TestPostDispatchHook.sol index 413a8dbb7..ddf357979 100644 --- a/solidity/contracts/test/TestPostDispatchHook.sol +++ b/solidity/contracts/test/TestPostDispatchHook.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.8.0; -import {AbstractPostDispatchHook} from "../hooks/AbstractPostDispatchHook.sol"; +import {AbstractPostDispatchHook} from "../hooks/libs/AbstractPostDispatchHook.sol"; contract TestPostDispatchHook is AbstractPostDispatchHook { // ============ Public Storage ============ diff --git a/solidity/contracts/test/TestQuery.sol b/solidity/contracts/test/TestQuery.sol index 2358cdb33..8d8372c99 100644 --- a/solidity/contracts/test/TestQuery.sol +++ b/solidity/contracts/test/TestQuery.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.13; import {InterchainQueryRouter} from "../middleware/InterchainQueryRouter.sol"; import {TypeCasts} from "../libs/TypeCasts.sol"; -import {CallLib} from "../libs/Call.sol"; +import {CallLib} from "../middleware/libs/Call.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/solidity/contracts/test/TestQuerySender.sol b/solidity/contracts/test/TestQuerySender.sol index e1a479461..7d218e55c 100644 --- a/solidity/contracts/test/TestQuerySender.sol +++ b/solidity/contracts/test/TestQuerySender.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.8.0; -import {IInterchainQueryRouter} from "../interfaces/middleware/IInterchainQueryRouter.sol"; -import {CallLib} from "../libs/Call.sol"; +import {InterchainQueryRouter} from "../middleware/InterchainQueryRouter.sol"; +import {CallLib} from "../middleware/libs/Call.sol"; contract TestQuerySender { - IInterchainQueryRouter queryRouter; + InterchainQueryRouter queryRouter; address public lastAddressResult; uint256 public lastUint256Result; @@ -16,7 +16,7 @@ contract TestQuerySender { event ReceivedBytes32Result(bytes32 result); function initialize(address _queryRouterAddress) external { - queryRouter = IInterchainQueryRouter(_queryRouterAddress); + queryRouter = InterchainQueryRouter(_queryRouterAddress); } function queryAddress( diff --git a/solidity/contracts/test/TestRouter.sol b/solidity/contracts/test/TestRouter.sol index 028a1cc7b..ceca137a7 100644 --- a/solidity/contracts/test/TestRouter.sol +++ b/solidity/contracts/test/TestRouter.sol @@ -1,13 +1,20 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.6.11; -import "../Router.sol"; +import "../client/Router.sol"; contract TestRouter is Router { event InitializeOverload(); constructor(address _mailbox) Router(_mailbox) {} + function initialize(address _hook, address _interchainSecurityModule) + public + initializer + { + _MailboxClient_initialize(_hook, _interchainSecurityModule, msg.sender); + } + function _handle( uint32, bytes32, diff --git a/solidity/contracts/test/bad-recipient/BadRecipient1.sol b/solidity/contracts/test/bad-recipient/BadRecipient1.sol deleted file mode 100644 index e89af8e78..000000000 --- a/solidity/contracts/test/bad-recipient/BadRecipient1.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.8.0; - -import {IMessageRecipient} from "../../interfaces/IMessageRecipient.sol"; - -contract BadRecipient1 is IMessageRecipient { - function handle( - uint32, - bytes32, - bytes calldata - ) external payable override { - assembly { - revert(0, 0) - } - } -} diff --git a/solidity/contracts/test/bad-recipient/BadRecipient2.sol b/solidity/contracts/test/bad-recipient/BadRecipient2.sol deleted file mode 100644 index 41760bb4b..000000000 --- a/solidity/contracts/test/bad-recipient/BadRecipient2.sol +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.8.0; - -contract BadRecipient2 { - function handle(uint32, bytes32) external pure {} // solhint-disable-line no-empty-blocks -} diff --git a/solidity/contracts/test/bad-recipient/BadRecipient3.sol b/solidity/contracts/test/bad-recipient/BadRecipient3.sol deleted file mode 100644 index 91638fb77..000000000 --- a/solidity/contracts/test/bad-recipient/BadRecipient3.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.8.0; - -import {IMessageRecipient} from "../../interfaces/IMessageRecipient.sol"; - -contract BadRecipient3 is IMessageRecipient { - function handle( - uint32, - bytes32, - bytes calldata - ) external payable override { - assembly { - mstore(0, 0xabcdef) - revert(0, 32) - } - } -} diff --git a/solidity/contracts/test/bad-recipient/BadRecipient5.sol b/solidity/contracts/test/bad-recipient/BadRecipient5.sol deleted file mode 100644 index 2101907ad..000000000 --- a/solidity/contracts/test/bad-recipient/BadRecipient5.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.8.0; - -import {IMessageRecipient} from "../../interfaces/IMessageRecipient.sol"; - -contract BadRecipient5 is IMessageRecipient { - function handle( - uint32, - bytes32, - bytes calldata - ) external payable override { - require(false, "no can do"); - } -} diff --git a/solidity/contracts/test/bad-recipient/BadRecipient6.sol b/solidity/contracts/test/bad-recipient/BadRecipient6.sol deleted file mode 100644 index f6e6ce901..000000000 --- a/solidity/contracts/test/bad-recipient/BadRecipient6.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity >=0.8.0; - -import {IMessageRecipient} from "../../interfaces/IMessageRecipient.sol"; - -contract BadRecipient6 is IMessageRecipient { - function handle( - uint32, - bytes32, - bytes calldata - ) external payable override { - require(false); // solhint-disable-line reason-string - } -} diff --git a/typescript/token/contracts/HypERC20.sol b/solidity/contracts/token/HypERC20.sol similarity index 91% rename from typescript/token/contracts/HypERC20.sol rename to solidity/contracts/token/HypERC20.sol index 8b765f572..1dac128a8 100644 --- a/typescript/token/contracts/HypERC20.sol +++ b/solidity/contracts/token/HypERC20.sol @@ -13,26 +13,21 @@ import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ contract HypERC20 is ERC20Upgradeable, TokenRouter { uint8 private immutable _decimals; - constructor(uint8 __decimals) { + constructor(uint8 __decimals, address _mailbox) TokenRouter(_mailbox) { _decimals = __decimals; } /** * @notice Initializes the Hyperlane router, ERC20 metadata, and mints initial supply to deployer. - * @param _mailbox The address of the mailbox contract. * @param _totalSupply The initial supply of the token. * @param _name The name of the token. * @param _symbol The symbol of the token. */ function initialize( - address _mailbox, uint256 _totalSupply, string memory _name, string memory _symbol ) external initializer { - // initialize router - __Router_initialize(_mailbox); - // Initialize ERC20 metadata __ERC20_init(_name, _symbol); _mint(msg.sender, _totalSupply); diff --git a/typescript/token/contracts/HypERC20Collateral.sol b/solidity/contracts/token/HypERC20Collateral.sol similarity index 83% rename from typescript/token/contracts/HypERC20Collateral.sol rename to solidity/contracts/token/HypERC20Collateral.sol index 2e9cb4966..6bde836c0 100644 --- a/typescript/token/contracts/HypERC20Collateral.sol +++ b/solidity/contracts/token/HypERC20Collateral.sol @@ -2,7 +2,8 @@ pragma solidity >=0.8.0; import {TokenRouter} from "./libs/TokenRouter.sol"; -import {Message} from "./libs/Message.sol"; +import {TokenMessage} from "./libs/TokenMessage.sol"; +import {MailboxClient} from "../client/MailboxClient.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -20,18 +21,10 @@ contract HypERC20Collateral is TokenRouter { * @notice Constructor * @param erc20 Address of the token to keep as collateral */ - constructor(address erc20) { + constructor(address erc20, address _mailbox) TokenRouter(_mailbox) { wrappedToken = IERC20(erc20); } - /** - * @notice Initializes the Hyperlane router. - * @param _mailbox The address of the mailbox contract. - */ - function initialize(address _mailbox) external initializer { - __Router_initialize(_mailbox); - } - function balanceOf(address _account) external view diff --git a/typescript/token/contracts/HypERC721.sol b/solidity/contracts/token/HypERC721.sol similarity index 90% rename from typescript/token/contracts/HypERC721.sol rename to solidity/contracts/token/HypERC721.sol index 24aa971cd..cc69d9556 100644 --- a/typescript/token/contracts/HypERC721.sol +++ b/solidity/contracts/token/HypERC721.sol @@ -12,25 +12,25 @@ import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/t * @author Abacus Works */ contract HypERC721 is ERC721EnumerableUpgradeable, TokenRouter { + constructor(address _mailbox) TokenRouter(_mailbox) {} + /** * @notice Initializes the Hyperlane router, ERC721 metadata, and mints initial supply to deployer. - * @param _mailbox The address of the mailbox contract. * @param _mintAmount The amount of NFTs to mint to `msg.sender`. * @param _name The name of the token. * @param _symbol The symbol of the token. */ function initialize( - address _mailbox, uint256 _mintAmount, string memory _name, string memory _symbol ) external initializer { - // transfers ownership to `msg.sender` - __Router_initialize(_mailbox); + address owner = msg.sender; + _transferOwnership(owner); __ERC721_init(_name, _symbol); for (uint256 i = 0; i < _mintAmount; i++) { - _safeMint(msg.sender, i); + _safeMint(owner, i); } } diff --git a/typescript/token/contracts/HypERC721Collateral.sol b/solidity/contracts/token/HypERC721Collateral.sol similarity index 85% rename from typescript/token/contracts/HypERC721Collateral.sol rename to solidity/contracts/token/HypERC721Collateral.sol index c9d876c5e..890d4698b 100644 --- a/typescript/token/contracts/HypERC721Collateral.sol +++ b/solidity/contracts/token/HypERC721Collateral.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.0; import {TokenRouter} from "./libs/TokenRouter.sol"; -import {Message} from "./libs/Message.sol"; +import {TokenMessage} from "./libs/TokenMessage.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; @@ -17,7 +17,7 @@ contract HypERC721Collateral is TokenRouter { * @notice Constructor * @param erc721 Address of the token to keep as collateral */ - constructor(address erc721) { + constructor(address erc721, address _mailbox) TokenRouter(_mailbox) { wrappedToken = IERC721(erc721); } @@ -25,14 +25,6 @@ contract HypERC721Collateral is TokenRouter { return IERC721(wrappedToken).ownerOf(_tokenId); } - /** - * @notice Initializes the Hyperlane router. - * @param _mailbox The address of the mailbox contract. - */ - function initialize(address _mailbox) external initializer { - __Router_initialize(_mailbox); - } - /** * @dev Returns the balance of `_account` for `wrappedToken`. * @inheritdoc TokenRouter diff --git a/typescript/token/contracts/HypNative.sol b/solidity/contracts/token/HypNative.sol similarity index 85% rename from typescript/token/contracts/HypNative.sol rename to solidity/contracts/token/HypNative.sol index bbe134cdb..6299dcf82 100644 --- a/typescript/token/contracts/HypNative.sol +++ b/solidity/contracts/token/HypNative.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.0; import {TokenRouter} from "./libs/TokenRouter.sol"; -import {Message} from "./libs/Message.sol"; +import {TokenMessage} from "./libs/TokenMessage.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; /** @@ -18,14 +18,7 @@ contract HypNative is TokenRouter { */ event Donation(address indexed sender, uint256 amount); - /** - * @notice Initializes the Hyperlane router, ERC20 metadata, and mints initial supply to deployer. - * @param _mailbox The address of the mailbox contract. - */ - function initialize(address _mailbox) external initializer { - // transfers ownership to `msg.sender` - __Router_initialize(_mailbox); - } + constructor(address _mailbox) TokenRouter(_mailbox) {} /** * @inheritdoc TokenRouter diff --git a/typescript/token/README.md b/solidity/contracts/token/README.md similarity index 100% rename from typescript/token/README.md rename to solidity/contracts/token/README.md diff --git a/typescript/token/contracts/extensions/HypERC721URICollateral.sol b/solidity/contracts/token/extensions/HypERC721URICollateral.sol similarity index 91% rename from typescript/token/contracts/extensions/HypERC721URICollateral.sol rename to solidity/contracts/token/extensions/HypERC721URICollateral.sol index 8a1abcb00..e03f5e5ff 100644 --- a/typescript/token/contracts/extensions/HypERC721URICollateral.sol +++ b/solidity/contracts/token/extensions/HypERC721URICollateral.sol @@ -11,7 +11,9 @@ import {IERC721MetadataUpgradeable} from "@openzeppelin/contracts-upgradeable/to */ contract HypERC721URICollateral is HypERC721Collateral { // solhint-disable-next-line no-empty-blocks - constructor(address erc721) HypERC721Collateral(erc721) {} + constructor(address erc721, address _mailbox) + HypERC721Collateral(erc721, _mailbox) + {} /** * @dev Transfers `_tokenId` of `wrappedToken` from `msg.sender` to this contract. diff --git a/typescript/token/contracts/extensions/HypERC721URIStorage.sol b/solidity/contracts/token/extensions/HypERC721URIStorage.sol similarity index 97% rename from typescript/token/contracts/extensions/HypERC721URIStorage.sol rename to solidity/contracts/token/extensions/HypERC721URIStorage.sol index 7c45b7b36..75785d55e 100644 --- a/typescript/token/contracts/extensions/HypERC721URIStorage.sol +++ b/solidity/contracts/token/extensions/HypERC721URIStorage.sol @@ -12,6 +12,8 @@ import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC72 * @author Abacus Works */ contract HypERC721URIStorage is HypERC721, ERC721URIStorageUpgradeable { + constructor(address _mailbox) HypERC721(_mailbox) {} + function balanceOf(address account) public view diff --git a/typescript/token/contracts/extensions/HypNativeScaled.sol b/solidity/contracts/token/extensions/HypNativeScaled.sol similarity index 95% rename from typescript/token/contracts/extensions/HypNativeScaled.sol rename to solidity/contracts/token/extensions/HypNativeScaled.sol index d187be416..34b1e3ce4 100644 --- a/typescript/token/contracts/extensions/HypNativeScaled.sol +++ b/solidity/contracts/token/extensions/HypNativeScaled.sol @@ -13,7 +13,7 @@ import {TokenRouter} from "../libs/TokenRouter.sol"; contract HypNativeScaled is HypNative { uint256 public immutable scale; - constructor(uint256 _scale) { + constructor(uint256 _scale, address _mailbox) HypNative(_mailbox) { scale = _scale; } diff --git a/typescript/token/contracts/libs/Message.sol b/solidity/contracts/token/libs/TokenMessage.sol similarity index 97% rename from typescript/token/contracts/libs/Message.sol rename to solidity/contracts/token/libs/TokenMessage.sol index 887188a34..8fc2e455f 100644 --- a/typescript/token/contracts/libs/Message.sol +++ b/solidity/contracts/token/libs/TokenMessage.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.8.0; -library Message { +library TokenMessage { function format( bytes32 _recipient, uint256 _amount, diff --git a/typescript/token/contracts/libs/TokenRouter.sol b/solidity/contracts/token/libs/TokenRouter.sol similarity index 92% rename from typescript/token/contracts/libs/TokenRouter.sol rename to solidity/contracts/token/libs/TokenRouter.sol index 3925c8fb2..76feee927 100644 --- a/typescript/token/contracts/libs/TokenRouter.sol +++ b/solidity/contracts/token/libs/TokenRouter.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.0; -import {GasRouter} from "@hyperlane-xyz/core/contracts/GasRouter.sol"; -import {TypeCasts} from "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol"; -import {Message} from "./Message.sol"; +import {GasRouter} from "../../client/GasRouter.sol"; +import {MailboxClient} from "../../client/MailboxClient.sol"; +import {TypeCasts} from "../../libs/TypeCasts.sol"; +import {TokenMessage} from "./TokenMessage.sol"; /** * @title Hyperlane Token Router that extends Router with abstract token (ERC20/ERC721) remote transfer functionality. @@ -12,7 +13,7 @@ import {Message} from "./Message.sol"; abstract contract TokenRouter is GasRouter { using TypeCasts for bytes32; using TypeCasts for address; - using Message for bytes; + using TokenMessage for bytes; /** * @dev Emitted on `transferRemote` when a transfer message is dispatched. @@ -38,6 +39,8 @@ abstract contract TokenRouter is GasRouter { uint256 amount ); + constructor(address _mailbox) GasRouter(_mailbox) {} + /** * @notice Transfers `_amountOrId` token to `_recipient` on `_destination` domain. * @dev Delegates transfer logic to `_transferFromSender` implementation. @@ -73,11 +76,10 @@ abstract contract TokenRouter is GasRouter { uint256 _gasPayment ) internal returns (bytes32 messageId) { bytes memory metadata = _transferFromSender(_amountOrId); - messageId = _dispatchWithGas( + messageId = _dispatch( _destination, - Message.format(_recipient, _amountOrId, metadata), _gasPayment, - msg.sender // refund address + TokenMessage.format(_recipient, _amountOrId, metadata) ); emit SentTransferRemote(_destination, _recipient, _amountOrId); } diff --git a/solidity/coverage.sh b/solidity/coverage.sh new file mode 100755 index 000000000..ba4437113 --- /dev/null +++ b/solidity/coverage.sh @@ -0,0 +1,21 @@ +# generates lcov.info +forge coverage --report lcov + +if ! command -v lcov &>/dev/null; then + echo "lcov is not installed. Installing..." + sudo apt-get install lcov +fi + +lcov --version + +# forge does not instrument libraries https://github.com/foundry-rs/foundry/issues/4854 +EXCLUDE="*test* *mock* *node_modules* $(grep -r 'library' contracts -l)" +lcov --rc lcov_branch_coverage=1 \ + --output-file forge-pruned-lcov.info \ + --remove lcov.info $EXCLUDE + +if [ "$CI" != "true" ]; then + genhtml --rc lcov_branch_coverage=1 \ + --output-directory coverage forge-pruned-lcov.info \ + && open coverage/index.html +fi diff --git a/solidity/package.json b/solidity/package.json index 238263a63..69a6757fc 100644 --- a/solidity/package.json +++ b/solidity/package.json @@ -47,8 +47,8 @@ "scripts": { "build": "hardhat compile && tsc", "lint": "solhint contracts/**/*.sol", - "clean": "hardhat clean && rm -rf ./dist ./cache ./types", - "coverage": "hardhat coverage && forge coverage --report lcov", + "clean": "hardhat clean && rm -rf ./dist ./cache ./types ./coverage", + "coverage": "./coverage.sh", "docs": "forge doc", "prettier": "prettier --write ./contracts ./test", "test": "hardhat test && forge test -vvv", diff --git a/solidity/test/InterchainAccountRouter.t.sol b/solidity/test/InterchainAccountRouter.t.sol index 955c55da1..cc63fee3f 100644 --- a/solidity/test/InterchainAccountRouter.t.sol +++ b/solidity/test/InterchainAccountRouter.t.sol @@ -8,10 +8,8 @@ import "../contracts/mock/MockHyperlaneEnvironment.sol"; import {TypeCasts} from "../contracts/libs/TypeCasts.sol"; import {IInterchainSecurityModule} from "../contracts/interfaces/IInterchainSecurityModule.sol"; import {IInterchainGasPaymaster} from "../contracts/interfaces/IInterchainGasPaymaster.sol"; -import {InterchainAccountRouter} from "../contracts/middleware/InterchainAccountRouter.sol"; +import {CallLib, OwnableMulticall, InterchainAccountRouter} from "../contracts/middleware/InterchainAccountRouter.sol"; import {InterchainAccountIsm} from "../contracts/isms/routing/InterchainAccountIsm.sol"; -import {OwnableMulticall} from "../contracts/OwnableMulticall.sol"; -import {CallLib} from "../contracts/libs/Call.sol"; contract Callable { mapping(address => bytes32) public data; diff --git a/solidity/test/InterchainQueryRouter.t.sol b/solidity/test/InterchainQueryRouter.t.sol index ba96e03d7..9251d7b86 100644 --- a/solidity/test/InterchainQueryRouter.t.sol +++ b/solidity/test/InterchainQueryRouter.t.sol @@ -2,8 +2,7 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -import {InterchainQueryRouter} from "../contracts/middleware/InterchainQueryRouter.sol"; -import {IInterchainQueryRouter} from "../contracts/interfaces/middleware/IInterchainQueryRouter.sol"; +import {CallLib, InterchainQueryRouter} from "../contracts/middleware/InterchainQueryRouter.sol"; import {MockHyperlaneEnvironment} from "../contracts/mock/MockHyperlaneEnvironment.sol"; import {MockToken} from "../contracts/mock/MockToken.sol"; @@ -11,7 +10,6 @@ import {PausableHook} from "../contracts/hooks/PausableHook.sol"; import {TypeCasts} from "../contracts/libs/TypeCasts.sol"; import "../contracts/test/TestRecipient.sol"; -import {CallLib} from "../contracts/libs/Call.sol"; contract InterchainQueryRouterTest is Test { using TypeCasts for address; diff --git a/solidity/test/Mailbox.t.sol b/solidity/test/Mailbox.t.sol index 3afd16b1a..e408b4b01 100644 --- a/solidity/test/Mailbox.t.sol +++ b/solidity/test/Mailbox.t.sol @@ -10,7 +10,7 @@ import "../contracts/test/TestIsm.sol"; import "../contracts/test/TestRecipient.sol"; import "../contracts/hooks/MerkleTreeHook.sol"; -import {StandardHookMetadata} from "../contracts/libs/hooks/StandardHookMetadata.sol"; +import {StandardHookMetadata} from "../contracts/hooks/libs/StandardHookMetadata.sol"; import {TypeCasts} from "../contracts/libs/TypeCasts.sol"; contract MailboxTest is Test, Versioned { diff --git a/solidity/test/ValidatorAnnounce.t.sol b/solidity/test/ValidatorAnnounce.t.sol index 32a1e0626..abc5d4e99 100644 --- a/solidity/test/ValidatorAnnounce.t.sol +++ b/solidity/test/ValidatorAnnounce.t.sol @@ -3,9 +3,8 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; import "../contracts/mock/MockMailbox.sol"; -import "../contracts/ValidatorAnnounce.sol"; +import "../contracts/isms/multisig/ValidatorAnnounce.sol"; import {TypeCasts} from "../contracts/libs/TypeCasts.sol"; -import {ValidatorAnnouncements} from "../contracts/libs/ValidatorAnnouncements.sol"; contract ValidatorAnnounceTest is Test { using TypeCasts for address; @@ -25,18 +24,17 @@ contract ValidatorAnnounceTest is Test { valAnnounce = new ValidatorAnnounce(address(mailbox)); } - function announce(uint256 privateKey, string memory storageLocation) - internal - { - bytes32 digest = ValidatorAnnouncements.getAnnouncementDigest( - address(mailbox), - localDomain, - storageLocation - ); + function announce( + uint256 privateKey, + string memory storageLocation, + bool shouldRevert + ) internal { + bytes32 digest = valAnnounce.getAnnouncementDigest(storageLocation); (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest); bytes memory signature = abi.encodePacked(r, s, v); address validator = vm.addr(privateKey); + if (shouldRevert) vm.expectRevert("replay"); valAnnounce.announce(validator, storageLocation, signature); } @@ -61,7 +59,7 @@ contract ValidatorAnnounceTest is Test { string memory storageLocation1 = "s3://test-bucket/us-east-1"; vm.expectEmit(true, false, false, true, address(valAnnounce)); emit ValidatorAnnouncement(validator, storageLocation1); - announce(privateKey, storageLocation1); + announce(privateKey, storageLocation1, false); address[] memory expectedValidators = new address[](1); expectedValidators[0] = validator; @@ -80,14 +78,13 @@ contract ValidatorAnnounceTest is Test { ); // Shouldn't be able to announce the same location twice - vm.expectRevert("replay"); - announce(privateKey, storageLocation1); + announce(privateKey, storageLocation1, true); // Announce a second location string memory storageLocation2 = "s3://test-bucket-2/us-east-1"; vm.expectEmit(true, false, false, true, address(valAnnounce)); emit ValidatorAnnouncement(validator, storageLocation2); - announce(privateKey, storageLocation2); + announce(privateKey, storageLocation2, false); assertEqAddrArr( valAnnounce.getAnnouncedValidators(), expectedValidators diff --git a/solidity/test/hooks/DomainRoutingHook.t.sol b/solidity/test/hooks/DomainRoutingHook.t.sol index 278c19945..d8a3bcddf 100644 --- a/solidity/test/hooks/DomainRoutingHook.t.sol +++ b/solidity/test/hooks/DomainRoutingHook.t.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; -import {DomainRoutingHook} from "../../contracts/hooks/DomainRoutingHook.sol"; -import {FallbackDomainRoutingHook} from "../../contracts/hooks/FallbackDomainRoutingHook.sol"; +import {DomainRoutingHook} from "../../contracts/hooks/routing/DomainRoutingHook.sol"; +import {FallbackDomainRoutingHook} from "../../contracts/hooks/routing/FallbackDomainRoutingHook.sol"; import {TestPostDispatchHook} from "../../contracts/test/TestPostDispatchHook.sol"; import {TestMailbox} from "../../contracts/test/TestMailbox.sol"; diff --git a/solidity/test/hooks/StaticProtocolFee.t.sol b/solidity/test/hooks/StaticProtocolFee.t.sol index bf813c060..5f225b1ae 100644 --- a/solidity/test/hooks/StaticProtocolFee.t.sol +++ b/solidity/test/hooks/StaticProtocolFee.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.13; import {Test} from "forge-std/Test.sol"; import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; import {MessageUtils} from "../isms/IsmTestUtils.sol"; -import {StandardHookMetadata} from "../../contracts/libs/hooks/StandardHookMetadata.sol"; +import {StandardHookMetadata} from "../../contracts/hooks/libs/StandardHookMetadata.sol"; import {StaticProtocolFee} from "../../contracts/hooks/StaticProtocolFee.sol"; diff --git a/solidity/test/igps/InterchainGasPaymaster.t.sol b/solidity/test/igps/InterchainGasPaymaster.t.sol index 67962c547..cd2dc3f06 100644 --- a/solidity/test/igps/InterchainGasPaymaster.t.sol +++ b/solidity/test/igps/InterchainGasPaymaster.t.sol @@ -3,12 +3,12 @@ pragma solidity ^0.8.13; import {Test} from "forge-std/Test.sol"; -import {StandardHookMetadata} from "../../contracts/libs/hooks/StandardHookMetadata.sol"; +import {StandardHookMetadata} from "../../contracts/hooks/libs/StandardHookMetadata.sol"; import {Message} from "../../contracts/libs/Message.sol"; import {MessageUtils} from "../isms/IsmTestUtils.sol"; import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; -import {InterchainGasPaymaster} from "../../contracts/igps/InterchainGasPaymaster.sol"; -import {StorageGasOracle} from "../../contracts/igps/gas-oracles/StorageGasOracle.sol"; +import {InterchainGasPaymaster} from "../../contracts/hooks/igp/InterchainGasPaymaster.sol"; +import {StorageGasOracle} from "../../contracts/hooks/igp/StorageGasOracle.sol"; import {IGasOracle} from "../../contracts/interfaces/IGasOracle.sol"; contract InterchainGasPaymasterTest is Test { diff --git a/solidity/test/igps/OverheadIgp.t.sol b/solidity/test/igps/OverheadIgp.t.sol index 0e2b3ab62..769c3d1d5 100644 --- a/solidity/test/igps/OverheadIgp.t.sol +++ b/solidity/test/igps/OverheadIgp.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.13; import {Test} from "forge-std/Test.sol"; -import {OverheadIgp} from "../../contracts/igps/OverheadIgp.sol"; +import {OverheadIgp} from "../../contracts/hooks/igp/OverheadIgp.sol"; import {TestInterchainGasPaymaster} from "../../contracts/test/TestInterchainGasPaymaster.sol"; contract OverheadIgpTest is Test { diff --git a/solidity/test/igps/gas-oracles/StorageGasOracle.t.sol b/solidity/test/igps/gas-oracles/StorageGasOracle.t.sol index a3f55d777..4ed164d22 100644 --- a/solidity/test/igps/gas-oracles/StorageGasOracle.t.sol +++ b/solidity/test/igps/gas-oracles/StorageGasOracle.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.13; import {Test} from "forge-std/Test.sol"; -import {StorageGasOracle} from "../../../contracts/igps/gas-oracles/StorageGasOracle.sol"; +import {StorageGasOracle} from "../../../contracts/hooks/igp/StorageGasOracle.sol"; import {IGasOracle} from "../../../contracts/interfaces/IGasOracle.sol"; contract StorageGasOracleTest is Test { diff --git a/solidity/test/isms/AggregationIsm.t.sol b/solidity/test/isms/AggregationIsm.t.sol index 9bc727315..1b8075e98 100644 --- a/solidity/test/isms/AggregationIsm.t.sol +++ b/solidity/test/isms/AggregationIsm.t.sol @@ -5,7 +5,7 @@ import "forge-std/Test.sol"; import {IAggregationIsm} from "../../contracts/interfaces/isms/IAggregationIsm.sol"; import {StaticAggregationIsmFactory} from "../../contracts/isms/aggregation/StaticAggregationIsmFactory.sol"; -import {AggregationIsmMetadata} from "../../contracts/libs/isms/AggregationIsmMetadata.sol"; +import {AggregationIsmMetadata} from "../../contracts/isms/libs/AggregationIsmMetadata.sol"; import {TestIsm, MOfNTestUtils} from "./IsmTestUtils.sol"; contract AggregationIsmTest is Test { diff --git a/solidity/test/isms/ERC5164ISM.t.sol b/solidity/test/isms/ERC5164ISM.t.sol index f8621d98a..a2e04ffa2 100644 --- a/solidity/test/isms/ERC5164ISM.t.sol +++ b/solidity/test/isms/ERC5164ISM.t.sol @@ -9,7 +9,7 @@ import {MessageUtils} from "./IsmTestUtils.sol"; import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; import {IMessageDispatcher} from "../../contracts/interfaces/hooks/IMessageDispatcher.sol"; -import {ERC5164Hook} from "../../contracts/hooks/ERC5164Hook.sol"; +import {ERC5164Hook} from "../../contracts/hooks/aggregation/ERC5164Hook.sol"; import {AbstractMessageIdAuthorizedIsm} from "../../contracts/isms/hook/AbstractMessageIdAuthorizedIsm.sol"; import {ERC5164Ism} from "../../contracts/isms/hook/ERC5164Ism.sol"; import {TestMailbox} from "../../contracts/test/TestMailbox.sol"; diff --git a/solidity/test/isms/MultisigIsm.t.sol b/solidity/test/isms/MultisigIsm.t.sol index 154e863f2..ea567e9de 100644 --- a/solidity/test/isms/MultisigIsm.t.sol +++ b/solidity/test/isms/MultisigIsm.t.sol @@ -6,7 +6,7 @@ import "forge-std/Test.sol"; import {IMultisigIsm} from "../../contracts/interfaces/isms/IMultisigIsm.sol"; import {TestMailbox} from "../../contracts/test/TestMailbox.sol"; import {StaticMerkleRootMultisigIsmFactory, StaticMessageIdMultisigIsmFactory} from "../../contracts/isms/multisig/StaticMultisigIsm.sol"; -import {MerkleRootMultisigIsmMetadata} from "../../contracts/libs/isms/MerkleRootMultisigIsmMetadata.sol"; +import {MerkleRootMultisigIsmMetadata} from "../../contracts/isms/libs/MerkleRootMultisigIsmMetadata.sol"; import {CheckpointLib} from "../../contracts/libs/CheckpointLib.sol"; import {StaticMOfNAddressSetFactory} from "../../contracts/libs/StaticMOfNAddressSetFactory.sol"; import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; diff --git a/solidity/test/isms/OPStackIsm.t.sol b/solidity/test/isms/OPStackIsm.t.sol index e97725bcb..0afc733da 100644 --- a/solidity/test/isms/OPStackIsm.t.sol +++ b/solidity/test/isms/OPStackIsm.t.sol @@ -5,8 +5,8 @@ import {Test} from "forge-std/Test.sol"; import {LibBit} from "../../contracts/libs/LibBit.sol"; import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; -import {StandardHookMetadata} from "../../contracts/libs/hooks/StandardHookMetadata.sol"; -import {StandardHookMetadata} from "../../contracts/libs/hooks/StandardHookMetadata.sol"; +import {StandardHookMetadata} from "../../contracts/hooks/libs/StandardHookMetadata.sol"; +import {StandardHookMetadata} from "../../contracts/hooks/libs/StandardHookMetadata.sol"; import {AbstractMessageIdAuthorizedIsm} from "../../contracts/isms/hook/AbstractMessageIdAuthorizedIsm.sol"; import {TestMailbox} from "../../contracts/test/TestMailbox.sol"; import {Message} from "../../contracts/libs/Message.sol"; @@ -15,7 +15,8 @@ import {TestMultisigIsm} from "../../contracts/test/TestMultisigIsm.sol"; import {OPStackIsm} from "../../contracts/isms/hook/OPStackIsm.sol"; import {OPStackHook} from "../../contracts/hooks/OPStackHook.sol"; import {TestRecipient} from "../../contracts/test/TestRecipient.sol"; -import {NotCrossChainCall} from "../../contracts/isms/hook/crossChainEnabled/errors.sol"; + +import {NotCrossChainCall} from "@openzeppelin/contracts/crosschain/errors.sol"; import {AddressAliasHelper} from "@eth-optimism/contracts/standards/AddressAliasHelper.sol"; import {ICrossDomainMessenger, IL2CrossDomainMessenger} from "../../contracts/interfaces/optimism/ICrossDomainMessenger.sol"; diff --git a/solidity/test/router.test.ts b/solidity/test/router.test.ts index e6ae6935a..da8fd646e 100644 --- a/solidity/test/router.test.ts +++ b/solidity/test/router.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-floating-promises */ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; import { expect } from 'chai'; -import { BigNumberish, ContractTransaction } from 'ethers'; +import { BigNumberish } from 'ethers'; import { ethers } from 'hardhat'; import { addressToBytes32 } from '@hyperlane-xyz/utils'; @@ -9,6 +9,7 @@ import { addressToBytes32 } from '@hyperlane-xyz/utils'; import { TestInterchainGasPaymaster, TestInterchainGasPaymaster__factory, + TestIsm, TestIsm__factory, TestMailbox, TestMailbox__factory, @@ -23,19 +24,11 @@ const destination = 2; const destinationWithoutRouter = 3; const body = '0xdeadbeef'; -interface GasPaymentParams { - // The amount of destination gas being paid for - gasAmount: BigNumberish; - // The amount of native tokens paid - payment: BigNumberish; - refundAddress: string; -} - -// TODO: update for v3 -describe.skip('Router', async () => { +describe('Router', async () => { let router: TestRouter, mailbox: TestMailbox, igp: TestInterchainGasPaymaster, + defaultIsm: TestIsm, signer: SignerWithAddress, nonOwner: SignerWithAddress; @@ -46,191 +39,146 @@ describe.skip('Router', async () => { beforeEach(async () => { const mailboxFactory = new TestMailbox__factory(signer); mailbox = await mailboxFactory.deploy(origin); - igp = await new TestInterchainGasPaymaster__factory(signer).deploy( - nonOwner.address, - ); + igp = await new TestInterchainGasPaymaster__factory(signer).deploy(); const requiredHook = await new TestMerkleTreeHook__factory(signer).deploy( mailbox.address, ); - const defaultIsm = await new TestIsm__factory(signer).deploy(); + defaultIsm = await new TestIsm__factory(signer).deploy(); await mailbox.initialize( signer.address, defaultIsm.address, igp.address, requiredHook.address, ); - router = await new TestRouter__factory(signer).deploy(); + router = await new TestRouter__factory(signer).deploy(mailbox.address); + await router.initialize(igp.address, defaultIsm.address); }); describe('#initialize', () => { - it('should set the mailbox', async () => { - await router.initialize(mailbox.address); - expect(await router.mailbox()).to.equal(mailbox.address); + it('should set the hook', async () => { + expect(await router.hook()).to.equal(igp.address); + }); + + it('should set the ism', async () => { + expect(await router.interchainSecurityModule()).to.equal( + defaultIsm.address, + ); }); it('should transfer owner to deployer', async () => { - await router.initialize(mailbox.address); expect(await router.owner()).to.equal(signer.address); }); it('cannot be initialized twice', async () => { - await router.initialize(mailbox.address); - await expect(router.initialize(mailbox.address)).to.be.revertedWith( - 'Initializable: contract is already initialized', - ); + await expect( + router.initialize(mailbox.address, defaultIsm.address), + ).to.be.revertedWith('Initializable: contract is already initialized'); }); }); - describe('when initialized', () => { - beforeEach(async () => { - await router.initialize(mailbox.address); - }); + it('accepts message from enrolled mailbox and router', async () => { + const sender = addressToBytes32(nonOwner.address); + await router.enrollRemoteRouter(origin, sender); + const recipient = addressToBytes32(router.address); + // Does not revert. + await mailbox.testHandle(origin, sender, recipient, body); + }); - it('accepts message from enrolled mailbox and router', async () => { - const sender = addressToBytes32(nonOwner.address); - await router.enrollRemoteRouter(origin, sender); - const recipient = addressToBytes32(router.address); - // Does not revert. - await mailbox.testHandle(origin, sender, recipient, body); - }); + it('rejects message from unenrolled mailbox', async () => { + await expect( + router.handle(origin, addressToBytes32(nonOwner.address), body), + ).to.be.revertedWith('MailboxClient: sender not mailbox'); + }); - it('rejects message from unenrolled mailbox', async () => { - await expect( - router.handle(origin, addressToBytes32(nonOwner.address), body), - ).to.be.revertedWith('!mailbox'); - }); + it('rejects message from unenrolled router', async () => { + const sender = addressToBytes32(nonOwner.address); + const recipient = addressToBytes32(router.address); + await expect( + mailbox.testHandle(origin, sender, recipient, body), + ).to.be.revertedWith(`No router enrolled for domain: ${origin}`); + }); - it('rejects message from unenrolled router', async () => { - const sender = addressToBytes32(nonOwner.address); - const recipient = addressToBytes32(router.address); - await expect( - mailbox.testHandle(origin, sender, recipient, body), - ).to.be.revertedWith( - `No router enrolled for domain. Did you specify the right domain ID?`, - ); - }); + it('owner can enroll remote router', async () => { + const remote = nonOwner.address; + const remoteBytes = addressToBytes32(nonOwner.address); + expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(false); + await expect(router.mustHaveRemoteRouter(origin)).to.be.revertedWith( + `No router enrolled for domain: ${origin}`, + ); + await router.enrollRemoteRouter(origin, addressToBytes32(remote)); + expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(true); + expect(await router.mustHaveRemoteRouter(origin)).to.equal(remoteBytes); + }); + + it('owner can enroll remote router using batch function', async () => { + const remote = nonOwner.address; + const remoteBytes = addressToBytes32(nonOwner.address); + expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(false); + await expect(router.mustHaveRemoteRouter(origin)).to.be.revertedWith( + `No router enrolled for domain: ${origin}`, + ); + await router.enrollRemoteRouters([origin], [addressToBytes32(remote)]); + expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(true); + expect(await router.mustHaveRemoteRouter(origin)).to.equal(remoteBytes); + }); - it('owner can enroll remote router', async () => { - const remote = nonOwner.address; - const remoteBytes = addressToBytes32(nonOwner.address); - expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(false); - await expect(router.mustHaveRemoteRouter(origin)).to.be.revertedWith( - `No router enrolled for domain. Did you specify the right domain ID?`, + describe('#domains', () => { + it('returns the domains', async () => { + await router.enrollRemoteRouters( + [origin, destination], + [ + addressToBytes32(nonOwner.address), + addressToBytes32(nonOwner.address), + ], ); - await router.enrollRemoteRouter(origin, addressToBytes32(remote)); - expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(true); - expect(await router.mustHaveRemoteRouter(origin)).to.equal(remoteBytes); + expect(await router.domains()).to.deep.equal([origin, destination]); }); + }); + + it('non-owner cannot enroll remote router', async () => { + await expect( + router + .connect(nonOwner) + .enrollRemoteRouter(origin, addressToBytes32(nonOwner.address)), + ).to.be.revertedWith(ONLY_OWNER_REVERT_MSG); + }); - it('owner can enroll remote router using batch function', async () => { - const remote = nonOwner.address; - const remoteBytes = addressToBytes32(nonOwner.address); - expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(false); - await expect(router.mustHaveRemoteRouter(origin)).to.be.revertedWith( - `No router enrolled for domain. Did you specify the right domain ID?`, + describe('#dispatch', () => { + let payment: BigNumberish; + + beforeEach(async () => { + // Enroll a remote router on the destination domain. + // The address is arbitrary because no messages will actually be processed. + await router.enrollRemoteRouter( + destination, + addressToBytes32(nonOwner.address), + ); + const recipient = addressToBytes32(router.address); + payment = await mailbox['quoteDispatch(uint32,bytes32,bytes)']( + destination, + recipient, + body, ); - await router.enrollRemoteRouters([origin], [addressToBytes32(remote)]); - expect(await router.isRemoteRouter(origin, remoteBytes)).to.equal(true); - expect(await router.mustHaveRemoteRouter(origin)).to.equal(remoteBytes); }); - describe('#domains', () => { - it('returns the domains', async () => { - await router.enrollRemoteRouters( - [origin, destination], - [ - addressToBytes32(nonOwner.address), - addressToBytes32(nonOwner.address), - ], - ); - expect(await router.domains()).to.deep.equal([origin, destination]); - }); + it('dispatches a message', async () => { + await expect( + router.dispatch(destination, body, { value: payment }), + ).to.emit(mailbox, 'Dispatch'); }); - it('non-owner cannot enroll remote router', async () => { + it('reverts on insufficient payment', async () => { await expect( - router - .connect(nonOwner) - .enrollRemoteRouter(origin, addressToBytes32(nonOwner.address)), - ).to.be.revertedWith(ONLY_OWNER_REVERT_MSG); + router.dispatch(destination, body, { value: payment.sub(1) }), + ).to.be.revertedWith('insufficient interchain gas payment'); }); - describe('dispatch functions', () => { - let payment: BigNumberish; - - beforeEach(async () => { - // Enroll a remote router on the destination domain. - // The address is arbitrary because no messages will actually be processed. - await router.enrollRemoteRouter( - destination, - addressToBytes32(nonOwner.address), - ); - const recipient = utils.addressToBytes32(router.address); - payment = await mailbox.quoteDispatch(destination, recipient, body); - }); - - describe('#dispatch', () => { - it('dispatches a message', async () => { - await expect( - router.dispatch(destination, body, { value: payment }), - ).to.emit(mailbox, 'Dispatch'); - }); - - it('reverts on insufficient payment', async () => { - await expect( - router.dispatch(destination, body, { value: payment.sub(1) }), - ).to.be.revertedWith('insufficient interchain gas payment'); - }); - - it('reverts when dispatching a message to an unenrolled remote router', async () => { - await expect( - router.dispatch(destinationWithoutRouter, body), - ).to.be.revertedWith( - `No router enrolled for domain. Did you specify the right domain ID?`, - ); - }); - }); - - describe('#dispatchWithGas', () => { - const testGasPaymentParams = { - gasAmount: 4321, - payment: 43210, - refundAddress: '0xc0ffee0000000000000000000000000000000000', - }; - - it('dispatches a message', async () => { - await expect( - router.dispatchWithGas( - destination, - body, - testGasPaymentParams.gasAmount, - testGasPaymentParams.payment, - testGasPaymentParams.refundAddress, - { value: testGasPaymentParams.payment }, - ), - ).to.emit(mailbox, 'Dispatch'); - }); - - it('uses custom igp metadata', async () => { - const tx = await router.dispatchWithGas( - destination, - body, - testGasPaymentParams.gasAmount, - testGasPaymentParams.payment, - testGasPaymentParams.refundAddress, - { value: testGasPaymentParams.payment }, - ); - - const messageId = await mailbox.latestDispatchedId(); - const required = await igp.quoteGasPayment( - destination, - testGasPaymentParams.gasAmount, - ); - expect(tx) - .to.emit(igp, 'GasPayment') - .withArgs(messageId, testGasPaymentParams.gasAmount, required); - }); - }); + it('reverts when dispatching a message to an unenrolled remote router', async () => { + await expect( + router.dispatch(destinationWithoutRouter, body), + ).to.be.revertedWith( + `No router enrolled for domain: ${destinationWithoutRouter}`, + ); }); }); }); diff --git a/typescript/token/test/HypERC20.t.sol b/solidity/test/token/HypERC20.t.sol similarity index 83% rename from typescript/token/test/HypERC20.t.sol rename to solidity/test/token/HypERC20.t.sol index 80d7a85e2..9cdfb3ff6 100644 --- a/typescript/token/test/HypERC20.t.sol +++ b/solidity/test/token/HypERC20.t.sol @@ -15,17 +15,17 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -import {TypeCasts} from "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol"; -import {TestMailbox} from "@hyperlane-xyz/core/contracts/test/TestMailbox.sol"; -import {TestPostDispatchHook} from "@hyperlane-xyz/core/contracts/test/TestPostDispatchHook.sol"; -import {TestInterchainGasPaymaster} from "@hyperlane-xyz/core/contracts/test/TestInterchainGasPaymaster.sol"; -import {GasRouter} from "@hyperlane-xyz/core/contracts/GasRouter.sol"; - -import {ERC20Test} from "../contracts/test/ERC20Test.sol"; -import {HypERC20} from "../contracts/HypERC20.sol"; -import {HypERC20Collateral} from "../contracts/HypERC20Collateral.sol"; -import {HypNative} from "../contracts/HypNative.sol"; -import {TokenRouter} from "../contracts/libs/TokenRouter.sol"; +import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; +import {TestMailbox} from "../../contracts/test/TestMailbox.sol"; +import {ERC20Test} from "../../contracts/test/ERC20Test.sol"; +import {TestPostDispatchHook} from "../../contracts/test/TestPostDispatchHook.sol"; +import {TestInterchainGasPaymaster} from "../../contracts/test/TestInterchainGasPaymaster.sol"; +import {GasRouter} from "../../contracts/client/GasRouter.sol"; + +import {HypERC20} from "../../contracts/token/HypERC20.sol"; +import {HypERC20Collateral} from "../../contracts/token/HypERC20Collateral.sol"; +import {HypNative} from "../../contracts/token/HypNative.sol"; +import {TokenRouter} from "../../contracts/token/libs/TokenRouter.sol"; abstract contract HypTokenTest is Test { using TypeCasts for address; @@ -35,7 +35,6 @@ abstract contract HypTokenTest is Test { uint256 internal constant TOTAL_SUPPLY = 1_000_000e18; uint256 internal REQUIRED_VALUE; // initialized in setUp uint256 internal constant GAS_LIMIT = 10_000; - uint256 internal IGP_GAS_PRICE; // initialized in test uint256 internal constant TRANSFER_AMT = 100e18; string internal constant NAME = "HyperlaneInu"; string internal constant SYMBOL = "HYP"; @@ -74,13 +73,8 @@ abstract contract HypTokenTest is Test { REQUIRED_VALUE = noopHook.quoteDispatch("", ""); - remoteToken = new HypERC20(DECIMALS); - remoteToken.initialize( - address(remoteMailbox), - TOTAL_SUPPLY, - NAME, - SYMBOL - ); + remoteToken = new HypERC20(DECIMALS, address(remoteMailbox)); + remoteToken.initialize(TOTAL_SUPPLY, NAME, SYMBOL); remoteToken.enrollRemoteRouter( ORIGIN, address(localToken).addressToBytes32() @@ -110,8 +104,7 @@ abstract contract HypTokenTest is Test { } function _setCustomGasConfig() internal { - localMailbox.setDefaultHook(address(igp)); - IGP_GAS_PRICE = igp.gasPrice(); + localToken.setHook(address(igp)); TokenRouter.GasRouterConfig[] memory config = new TokenRouter.GasRouterConfig[](1); @@ -180,15 +173,10 @@ contract HypERC20Test is HypTokenTest { function setUp() public override { super.setUp(); - localToken = new HypERC20(DECIMALS); + localToken = new HypERC20(DECIMALS, address(localMailbox)); erc20Token = HypERC20(address(localToken)); - erc20Token.initialize( - address(localMailbox), - TOTAL_SUPPLY, - NAME, - SYMBOL - ); + erc20Token.initialize(TOTAL_SUPPLY, NAME, SYMBOL); erc20Token.enrollRemoteRouter( DESTINATION, @@ -201,7 +189,7 @@ contract HypERC20Test is HypTokenTest { function testInitialize_revert_ifAlreadyInitialized() public { vm.expectRevert("Initializable: contract is already initialized"); - erc20Token.initialize(ALICE, TOTAL_SUPPLY, NAME, SYMBOL); + erc20Token.initialize(TOTAL_SUPPLY, NAME, SYMBOL); } function testTotalSupply() public { @@ -245,7 +233,7 @@ contract HypERC20Test is HypTokenTest { _performRemoteTransferAndGas( REQUIRED_VALUE, TRANSFER_AMT, - GAS_LIMIT * IGP_GAS_PRICE + GAS_LIMIT * igp.gasPrice() ); assertEq(erc20Token.balanceOf(ALICE), balanceBefore - TRANSFER_AMT); } @@ -258,12 +246,11 @@ contract HypERC20CollateralTest is HypTokenTest { function setUp() public override { super.setUp(); - localToken = new HypERC20Collateral(address(primaryToken)); - erc20Collateral = HypERC20Collateral(address(localToken)); - - HypERC20Collateral(address(localToken)).initialize( + localToken = new HypERC20Collateral( + address(primaryToken), address(localMailbox) ); + erc20Collateral = HypERC20Collateral(address(localToken)); erc20Collateral.enrollRemoteRouter( DESTINATION, @@ -276,10 +263,7 @@ contract HypERC20CollateralTest is HypTokenTest { _enrollRemoteTokenRouter(); } - function testInitialize_revert_ifAlreadyInitialized() public { - vm.expectRevert("Initializable: contract is already initialized"); - erc20Collateral.initialize(ALICE); - } + function testInitialize_revert_ifAlreadyInitialized() public {} function testRemoteTransfer() public { uint256 balanceBefore = localToken.balanceOf(ALICE); @@ -306,7 +290,7 @@ contract HypERC20CollateralTest is HypTokenTest { _performRemoteTransferAndGas( REQUIRED_VALUE, TRANSFER_AMT, - GAS_LIMIT * IGP_GAS_PRICE + GAS_LIMIT * igp.gasPrice() ); assertEq(localToken.balanceOf(ALICE), balanceBefore - TRANSFER_AMT); } @@ -319,11 +303,9 @@ contract HypNativeTest is HypTokenTest { function setUp() public override { super.setUp(); - localToken = new HypNative(); + localToken = new HypNative(address(localMailbox)); nativeToken = HypNative(payable(address(localToken))); - nativeToken.initialize(address(localMailbox)); - nativeToken.enrollRemoteRouter( DESTINATION, address(remoteToken).addressToBytes32() @@ -335,10 +317,7 @@ contract HypNativeTest is HypTokenTest { _enrollRemoteTokenRouter(); } - function testInitialize_revert_ifAlreadyInitialized() public { - vm.expectRevert("Initializable: contract is already initialized"); - nativeToken.initialize(ALICE); - } + function testInitialize_revert_ifAlreadyInitialized() public {} function testRemoteTransfer() public { _performRemoteTransferWithEmit( @@ -363,7 +342,7 @@ contract HypNativeTest is HypTokenTest { _performRemoteTransferAndGas( REQUIRED_VALUE, TRANSFER_AMT, - TRANSFER_AMT + GAS_LIMIT * IGP_GAS_PRICE + TRANSFER_AMT + GAS_LIMIT * igp.gasPrice() ); } } diff --git a/typescript/token/test/HypERC721.t.sol b/solidity/test/token/HypERC721.t.sol similarity index 84% rename from typescript/token/test/HypERC721.t.sol rename to solidity/test/token/HypERC721.t.sol index c42e7f041..9f1671720 100644 --- a/typescript/token/test/HypERC721.t.sol +++ b/solidity/test/token/HypERC721.t.sol @@ -15,19 +15,18 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; -import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; - -import {TestMailbox} from "@hyperlane-xyz/core/contracts/test/TestMailbox.sol"; -import {TestPostDispatchHook} from "@hyperlane-xyz/core/contracts/test/TestPostDispatchHook.sol"; -import {TypeCasts} from "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol"; +import {TestMailbox} from "../../contracts/test/TestMailbox.sol"; +import {TestPostDispatchHook} from "../../contracts/test/TestPostDispatchHook.sol"; +import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; -import {ERC721Test} from "../contracts/test/ERC721Test.sol"; -import {TokenRouter} from "../contracts/libs/TokenRouter.sol"; -import {HypERC721} from "../contracts/HypERC721.sol"; -import {HypERC721Collateral} from "../contracts/HypERC721Collateral.sol"; -import {HypERC721URIStorage} from "../contracts/extensions/HypERC721URIStorage.sol"; -import {HypERC721URICollateral} from "../contracts/extensions/HypERC721URICollateral.sol"; +import {ERC721Test} from "../../contracts/test/ERC721Test.sol"; +import {TokenRouter} from "../../contracts/token/libs/TokenRouter.sol"; +import {HypERC721} from "../../contracts/token/HypERC721.sol"; +import {HypERC721Collateral} from "../../contracts/token/HypERC721Collateral.sol"; +import {HypERC721URIStorage} from "../../contracts/token/extensions/HypERC721URIStorage.sol"; +import {HypERC721URICollateral} from "../../contracts/token/extensions/HypERC721URICollateral.sol"; +import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; abstract contract HypTokenTest is Test, IERC721Receiver { @@ -70,13 +69,16 @@ abstract contract HypTokenTest is Test, IERC721Receiver { remoteMailbox = new TestMailbox(DESTINATION); - remoteToken = new HypERC721Collateral(address(remotePrimaryToken)); + remoteToken = new HypERC721Collateral( + address(remotePrimaryToken), + address(remoteMailbox) + ); } function _deployRemoteToken(bool isCollateral) internal { if (isCollateral) { - remoteToken = new HypERC721Collateral(address(remotePrimaryToken)); - HypERC721Collateral(address(remoteToken)).initialize( + remoteToken = new HypERC721Collateral( + address(remotePrimaryToken), address(remoteMailbox) ); remotePrimaryToken.transferFrom( @@ -85,13 +87,9 @@ abstract contract HypTokenTest is Test, IERC721Receiver { 0 ); // need for processing messages } else { - remoteToken = new HypERC721(); - HypERC721(address(remoteToken)).initialize( - address(remoteMailbox), - 0, - NAME, - SYMBOL - ); + HypERC721 erc721 = new HypERC721(address(remoteMailbox)); + erc721.initialize(0, NAME, SYMBOL); + remoteToken = TokenRouter(address(erc721)); } remoteToken.enrollRemoteRouter( ORIGIN, @@ -152,10 +150,10 @@ contract HypERC721Test is HypTokenTest { function setUp() public virtual override { super.setUp(); - localToken = new HypERC721(); + localToken = new HypERC721(address(localMailbox)); hyp721 = HypERC721(address(localToken)); - hyp721.initialize(address(localMailbox), INITIAL_SUPPLY, NAME, SYMBOL); + hyp721.initialize(INITIAL_SUPPLY, NAME, SYMBOL); hyp721.enrollRemoteRouter( DESTINATION, @@ -165,7 +163,7 @@ contract HypERC721Test is HypTokenTest { function testInitialize_revert_ifAlreadyInitialized() public { vm.expectRevert("Initializable: contract is already initialized"); - hyp721.initialize(address(localMailbox), INITIAL_SUPPLY, NAME, SYMBOL); + hyp721.initialize(INITIAL_SUPPLY, NAME, SYMBOL); } function testTotalSupply() public { @@ -211,6 +209,8 @@ contract HypERC721Test is HypTokenTest { } contract MockHypERC721URIStorage is HypERC721URIStorage { + constructor(address mailbox) HypERC721URIStorage(mailbox) {} + function setTokenURI(uint256 tokenId, string memory uri) public { _setTokenURI(tokenId, uri); } @@ -224,15 +224,10 @@ contract HypERC721URIStorageTest is HypTokenTest { function setUp() public override { super.setUp(); - localToken = new MockHypERC721URIStorage(); + localToken = new MockHypERC721URIStorage(address(localMailbox)); hyp721Storage = MockHypERC721URIStorage(address(localToken)); - hyp721Storage.initialize( - address(localMailbox), - INITIAL_SUPPLY, - NAME, - SYMBOL - ); + hyp721Storage.initialize(INITIAL_SUPPLY, NAME, SYMBOL); hyp721Storage.setTokenURI(0, URI); hyp721Storage.enrollRemoteRouter( DESTINATION, @@ -258,11 +253,12 @@ contract HypERC721CollateralTest is HypTokenTest { function setUp() public override { super.setUp(); - localToken = new HypERC721Collateral(address(localPrimaryToken)); + localToken = new HypERC721Collateral( + address(localPrimaryToken), + address(localMailbox) + ); hyp721Collateral = HypERC721Collateral(address(localToken)); - hyp721Collateral.initialize(address(localMailbox)); - hyp721Collateral.enrollRemoteRouter( DESTINATION, address(remoteToken).addressToBytes32() @@ -275,10 +271,7 @@ contract HypERC721CollateralTest is HypTokenTest { ); } - function testInitialize_revert_ifAlreadyInitialized() public { - vm.expectRevert("Initializable: contract is already initialized"); - hyp721Collateral.initialize(ALICE); - } + function testInitialize_revert_ifAlreadyInitialized() public {} function testRemoteTransfer(bool isCollateral) public { localPrimaryToken.approve(address(hyp721Collateral), 0); @@ -321,10 +314,12 @@ contract HypERC721CollateralURIStorageTest is HypTokenTest { function setUp() public override { super.setUp(); - localToken = new HypERC721URICollateral(address(localPrimaryToken)); + localToken = new HypERC721URICollateral( + address(localPrimaryToken), + address(localMailbox) + ); hyp721URICollateral = HypERC721URICollateral(address(localToken)); - hyp721URICollateral.initialize(address(localMailbox)); hyp721URICollateral.enrollRemoteRouter( DESTINATION, address(remoteToken).addressToBytes32() diff --git a/typescript/token/test/HypNativeScaled.t.sol b/solidity/test/token/HypNativeScaled.t.sol similarity index 86% rename from typescript/token/test/HypNativeScaled.t.sol rename to solidity/test/token/HypNativeScaled.t.sol index 02bf3b8d8..8f8ba6913 100644 --- a/typescript/token/test/HypNativeScaled.t.sol +++ b/solidity/test/token/HypNativeScaled.t.sol @@ -3,10 +3,10 @@ pragma solidity >=0.8.0; import "forge-std/Test.sol"; -import {HypNativeScaled} from "../contracts/extensions/HypNativeScaled.sol"; -import {HypERC20} from "../contracts/HypERC20.sol"; -import {TypeCasts} from "@hyperlane-xyz/core/contracts/libs/TypeCasts.sol"; -import {MockHyperlaneEnvironment} from "@hyperlane-xyz/core/contracts/mock/MockHyperlaneEnvironment.sol"; +import {HypNativeScaled} from "../../contracts/token/extensions/HypNativeScaled.sol"; +import {HypERC20} from "../../contracts/token/HypERC20.sol"; +import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; +import {MockHyperlaneEnvironment} from "../../contracts/mock/MockHyperlaneEnvironment.sol"; contract HypNativeScaledTest is Test { uint32 nativeDomain = 1; @@ -37,16 +37,16 @@ contract HypNativeScaledTest is Test { function setUp() public { environment = new MockHyperlaneEnvironment(synthDomain, nativeDomain); - synth = new HypERC20(decimals); - synth.initialize( - address(environment.mailboxes(synthDomain)), - mintAmount * (10**decimals), - "Zebec BSC Token", - "ZBC" + synth = new HypERC20( + decimals, + address(environment.mailboxes(synthDomain)) ); + synth.initialize(mintAmount * (10**decimals), "Zebec BSC Token", "ZBC"); - native = new HypNativeScaled(scale); - native.initialize(address(environment.mailboxes(nativeDomain))); + native = new HypNativeScaled( + scale, + address(environment.mailboxes(nativeDomain)) + ); native.enrollRemoteRouter( synthDomain, diff --git a/typescript/helloworld/contracts/HelloWorld.sol b/typescript/helloworld/contracts/HelloWorld.sol index 578cbddac..1d58fb6b1 100644 --- a/typescript/helloworld/contracts/HelloWorld.sol +++ b/typescript/helloworld/contracts/HelloWorld.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.13; // ============ External Imports ============ -import {Router} from "@hyperlane-xyz/core/contracts/Router.sol"; +import {Router} from "@hyperlane-xyz/core/contracts/client/Router.sol"; +import {StandardHookMetadata} from "@hyperlane-xyz/core/contracts/hooks/libs/StandardHookMetadata.sol"; /* * @title The Hello World App @@ -42,13 +43,10 @@ contract HelloWorld is Router { uint256 handleGasAmount ); - constructor(address _mailbox, address _interchainGasPaymaster) { + constructor(address _mailbox, address _hook) Router(_mailbox) { // Transfer ownership of the contract to deployer _transferOwnership(msg.sender); - // Set the addresses for the Mailbox and IGP - // Alternatively, this could be done later in an initialize method - _setMailbox(_mailbox); - _setInterchainGasPaymaster(_interchainGasPaymaster); + setHook(_hook); } // ============ External functions ============ @@ -65,13 +63,7 @@ contract HelloWorld is Router { { sent += 1; sentTo[_destinationDomain] += 1; - _dispatchWithGas( - _destinationDomain, - bytes(_message), - HANDLE_GAS_AMOUNT, - msg.value, - msg.sender - ); + _dispatch(_destinationDomain, bytes(_message)); emit SentHelloWorld( mailbox.localDomain(), _destinationDomain, @@ -80,6 +72,12 @@ contract HelloWorld is Router { } // ============ Internal functions ============ + function _metadata( + uint32 /*_destinationDomain*/ + ) internal view override returns (bytes memory) { + return + StandardHookMetadata.formatMetadata(HANDLE_GAS_AMOUNT, msg.sender); + } /** * @notice Handles a message from a remote router. diff --git a/typescript/helloworld/package.json b/typescript/helloworld/package.json index 450bc4aa0..e20faaa99 100644 --- a/typescript/helloworld/package.json +++ b/typescript/helloworld/package.json @@ -3,6 +3,7 @@ "description": "A basic skeleton of an Hyperlane app", "version": "1.5.0", "dependencies": { + "@hyperlane-xyz/core": "1.5.0", "@hyperlane-xyz/sdk": "1.5.0", "@openzeppelin/contracts-upgradeable": "^4.8.0", "ethers": "^5.7.2" diff --git a/typescript/helloworld/src/deploy/deploy.ts b/typescript/helloworld/src/deploy/deploy.ts index 33166be92..495b46cb5 100644 --- a/typescript/helloworld/src/deploy/deploy.ts +++ b/typescript/helloworld/src/deploy/deploy.ts @@ -1,3 +1,5 @@ +import { ethers } from 'ethers'; + import { ChainName, HyperlaneContracts, @@ -31,7 +33,7 @@ export class HelloWorldDeployer extends HyperlaneRouterDeployer< async deployContracts(chain: ChainName, config: HelloWorldConfig) { const router = await this.deployContract(chain, 'router', [ config.mailbox, - config.interchainGasPaymaster, + config.hook ?? ethers.constants.AddressZero, ]); return { router, diff --git a/typescript/helloworld/src/scripts/check.ts b/typescript/helloworld/src/scripts/check.ts index b4cd2ced3..9e9393071 100644 --- a/typescript/helloworld/src/scripts/check.ts +++ b/typescript/helloworld/src/scripts/check.ts @@ -1,9 +1,7 @@ import { HyperlaneCore, - HyperlaneIgp, MultiProvider, attachContractsMap, - createRouterConfigMap, } from '@hyperlane-xyz/sdk'; import { HelloWorldApp } from '../app/app'; @@ -27,13 +25,8 @@ async function check() { ); const core = HyperlaneCore.fromEnvironment('testnet', multiProvider); - const igp = HyperlaneIgp.fromEnvironment('testnet', multiProvider); const app = new HelloWorldApp(core, contractsMap, multiProvider); - const config = createRouterConfigMap( - ownerAddress, - core.contractsMap, - igp.contractsMap, - ); + const config = core.getRouterConfig(ownerAddress); console.info('Starting check'); const helloWorldChecker = new HelloWorldChecker(multiProvider, app, config); diff --git a/typescript/helloworld/src/scripts/deploy.ts b/typescript/helloworld/src/scripts/deploy.ts index b945a8dee..8fb157a91 100644 --- a/typescript/helloworld/src/scripts/deploy.ts +++ b/typescript/helloworld/src/scripts/deploy.ts @@ -2,9 +2,7 @@ import { Wallet } from 'ethers'; import { HyperlaneCore, - HyperlaneIgp, MultiProvider, - createRouterConfigMap, serializeContractsMap, } from '@hyperlane-xyz/sdk'; @@ -20,12 +18,7 @@ async function main() { multiProvider.setSharedSigner(signer); const core = HyperlaneCore.fromEnvironment('testnet', multiProvider); - const igp = HyperlaneIgp.fromEnvironment('testnet', multiProvider); - const config = createRouterConfigMap( - signer.address, - core.contractsMap, - igp.contractsMap, - ); + const config = core.getRouterConfig(signer.address); const deployer = new HelloWorldDeployer(multiProvider); const chainToContracts = await deployer.deploy(config); diff --git a/typescript/helloworld/src/test/deploy.test.ts b/typescript/helloworld/src/test/deploy.test.ts index bd189b68b..7a75c4ba5 100644 --- a/typescript/helloworld/src/test/deploy.test.ts +++ b/typescript/helloworld/src/test/deploy.test.ts @@ -7,7 +7,6 @@ import { MultiProvider, TestCoreApp, TestCoreDeployer, - deployTestIgpsAndGetRouterConfig, } from '@hyperlane-xyz/sdk'; import { HelloWorldApp } from '../app/app'; @@ -30,11 +29,7 @@ describe('deploy', async () => { const coreDeployer = new TestCoreDeployer(multiProvider); core = await coreDeployer.deployApp(); - config = await deployTestIgpsAndGetRouterConfig( - multiProvider, - signer.address, - core.contractsMap, - ); + config = core.getRouterConfig(signer.address); deployer = new HelloWorldDeployer(multiProvider); }); diff --git a/typescript/helloworld/src/test/helloworld.test.ts b/typescript/helloworld/src/test/helloworld.test.ts index eea91725f..5731720af 100644 --- a/typescript/helloworld/src/test/helloworld.test.ts +++ b/typescript/helloworld/src/test/helloworld.test.ts @@ -8,16 +8,11 @@ import { MultiProvider, TestCoreApp, TestCoreDeployer, - deployTestIgpsAndGetRouterConfig, } from '@hyperlane-xyz/sdk'; import { HelloWorldConfig } from '../deploy/config'; import { HelloWorldDeployer } from '../deploy/deploy'; -import { - HelloWorld, - IInterchainGasPaymaster, - IInterchainGasPaymaster__factory, -} from '../types'; +import { HelloWorld } from '../types'; describe('HelloWorld', async () => { const localChain = Chains.test1; @@ -28,26 +23,18 @@ describe('HelloWorld', async () => { let signer: SignerWithAddress; let local: HelloWorld; let remote: HelloWorld; - let localIgp: IInterchainGasPaymaster; let multiProvider: MultiProvider; let coreApp: TestCoreApp; let config: ChainMap; before(async () => { [signer] = await ethers.getSigners(); - multiProvider = MultiProvider.createTestMultiProvider({ signer }); + coreApp = await new TestCoreDeployer(multiProvider).deployApp(); + config = coreApp.getRouterConfig(signer.address); + localDomain = multiProvider.getDomainId(localChain); remoteDomain = multiProvider.getDomainId(remoteChain); - - const coreDeployer = new TestCoreDeployer(multiProvider); - const coreContractsMaps = await coreDeployer.deploy(); - coreApp = new TestCoreApp(coreContractsMaps, multiProvider); - config = await deployTestIgpsAndGetRouterConfig( - multiProvider, - signer.address, - coreContractsMaps, - ); }); beforeEach(async () => { @@ -56,10 +43,6 @@ describe('HelloWorld', async () => { local = contracts[localChain].router; remote = contracts[remoteChain].router; - localIgp = IInterchainGasPaymaster__factory.connect( - config[localChain].interchainGasPaymaster, - multiProvider.getProvider(localChain), - ); // The all counts start empty expect(await local.sent()).to.equal(0); @@ -68,19 +51,17 @@ describe('HelloWorld', async () => { expect(await remote.received()).to.equal(0); }); - async function quoteGasPayment( - fromRouter: HelloWorld, - destinationDomain: number, - igp: IInterchainGasPaymaster, - ) { - const handleGasAmount = await fromRouter.HANDLE_GAS_AMOUNT(); - return igp.quoteGasPayment(destinationDomain, handleGasAmount); + async function quoteGasPayment() { + const handleGasAmount = await local.HANDLE_GAS_AMOUNT(); + // TODO: update once IGP is not hardcoded in core deployer + const GAS_PRICE = 10; + return handleGasAmount.mul(GAS_PRICE); } it('sends a message', async () => { await expect( local.sendHelloWorld(remoteDomain, 'Hello', { - value: await quoteGasPayment(local, remoteDomain, localIgp), + value: await quoteGasPayment(), }), ).to.emit(local, 'SentHelloWorld'); // The sent counts are correct @@ -100,7 +81,7 @@ describe('HelloWorld', async () => { it('handles a message', async () => { await local.sendHelloWorld(remoteDomain, 'World', { - value: await quoteGasPayment(local, remoteDomain, localIgp), + value: await quoteGasPayment(), }); // Mock processing of the message by Hyperlane await coreApp.processOutboundMessages(localChain); diff --git a/typescript/infra/package.json b/typescript/infra/package.json index f638d6a96..1c3de0237 100644 --- a/typescript/infra/package.json +++ b/typescript/infra/package.json @@ -12,7 +12,6 @@ "@ethersproject/hardware-wallets": "^5.7.0", "@ethersproject/providers": "^5.7.2", "@hyperlane-xyz/helloworld": "1.5.0", - "@hyperlane-xyz/hyperlane-token": "1.5.0", "@hyperlane-xyz/sdk": "1.5.0", "@hyperlane-xyz/utils": "1.5.0", "@nomiclabs/hardhat-etherscan": "^3.0.3", diff --git a/typescript/infra/scripts/deploy.ts b/typescript/infra/scripts/deploy.ts index 7ce9d3a7c..40ce0608e 100644 --- a/typescript/infra/scripts/deploy.ts +++ b/typescript/infra/scripts/deploy.ts @@ -1,4 +1,3 @@ -import { getAddress } from 'ethers/lib/utils'; import path from 'path'; import { HelloWorldDeployer } from '@hyperlane-xyz/helloworld'; @@ -6,7 +5,6 @@ import { ChainMap, HyperlaneCoreDeployer, HyperlaneDeployer, - HyperlaneIgp, HyperlaneIgpDeployer, HyperlaneIsmFactory, HyperlaneIsmFactoryDeployer, @@ -22,7 +20,6 @@ import { deployWithArtifacts } from '../src/deployment/deploy'; import { TestQuerySenderDeployer } from '../src/deployment/testcontracts/testquerysender'; import { TestRecipientDeployer } from '../src/deployment/testcontracts/testrecipient'; import { impersonateAccount, useLocalProvider } from '../src/utils/fork'; -import { readJSON } from '../src/utils/utils'; import { Modules, @@ -105,10 +102,6 @@ async function main() { } else if (module === Modules.TEST_RECIPIENT) { deployer = new TestRecipientDeployer(multiProvider); } else if (module === Modules.TEST_QUERY_SENDER) { - const igp = HyperlaneIgp.fromEnvironment( - getAddresses(environment, Modules.INTERCHAIN_GAS_PAYMASTER), - multiProvider, - ); // Get query router addresses const queryAddresses = getAddresses( environment, @@ -117,7 +110,7 @@ async function main() { config = objMap(queryAddresses, (_c, conf) => ({ queryRouterAddress: conf.router, })); - deployer = new TestQuerySenderDeployer(multiProvider, igp); + deployer = new TestQuerySenderDeployer(multiProvider); } else if (module === Modules.HELLO_WORLD) { config = await getRouterConfig( environment, diff --git a/typescript/infra/scripts/utils.ts b/typescript/infra/scripts/utils.ts index 3aabf8836..136324e0c 100644 --- a/typescript/infra/scripts/utils.ts +++ b/typescript/infra/scripts/utils.ts @@ -40,12 +40,7 @@ import { fetchProvider } from '../src/config/chain'; import { EnvironmentNames, deployEnvToSdkEnv } from '../src/config/environment'; import { Role } from '../src/roles'; import { impersonateAccount, useLocalProvider } from '../src/utils/fork'; -import { - assertContext, - assertRole, - readJSON, - readJSONAtPath, -} from '../src/utils/utils'; +import { assertContext, assertRole, readJSON } from '../src/utils/utils'; export enum Modules { ISM_FACTORY = 'ism', @@ -345,8 +340,7 @@ export async function getRouterConfig( ? await multiProvider.getSignerAddress(chain) : owners[chain], mailbox: core.getContracts(chain).mailbox.address, - interchainGasPaymaster: - igp.getContracts(chain).defaultIsmInterchainGasPaymaster.address, + hook: igp.getContracts(chain).defaultIsmInterchainGasPaymaster.address, }; } return config; diff --git a/typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts b/typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts index f3c7ccb12..b864a2f6f 100644 --- a/typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts +++ b/typescript/infra/scripts/warp-routes/monitor-warp-routes-balances.ts @@ -3,16 +3,14 @@ import { ethers } from 'ethers'; import { Gauge, Registry } from 'prom-client'; import yargs from 'yargs'; -import { - ERC20__factory, - SealevelHypCollateralAdapter, - TokenType, -} from '@hyperlane-xyz/hyperlane-token'; +import { ERC20__factory } from '@hyperlane-xyz/core'; import { ChainMap, ChainName, MultiProtocolProvider, MultiProvider, + SealevelHypCollateralAdapter, + TokenType, } from '@hyperlane-xyz/sdk'; import { ProtocolType, diff --git a/typescript/infra/src/config/nautilus_token_config.ts b/typescript/infra/src/config/nautilus_token_config.ts index 74aef1637..3f4eb601f 100644 --- a/typescript/infra/src/config/nautilus_token_config.ts +++ b/typescript/infra/src/config/nautilus_token_config.ts @@ -1,5 +1,4 @@ -import { TokenType } from '@hyperlane-xyz/hyperlane-token'; -import { ChainMap } from '@hyperlane-xyz/sdk'; +import { ChainMap, TokenType } from '@hyperlane-xyz/sdk'; import { ProtocolType } from '@hyperlane-xyz/utils'; interface NativeTokenConfig { diff --git a/typescript/infra/src/deployment/testcontracts/testquerysender.ts b/typescript/infra/src/deployment/testcontracts/testquerysender.ts index b852e76fb..17c4c8b28 100644 --- a/typescript/infra/src/deployment/testcontracts/testquerysender.ts +++ b/typescript/infra/src/deployment/testcontracts/testquerysender.ts @@ -2,7 +2,6 @@ import { TestQuerySender__factory } from '@hyperlane-xyz/core'; import { ChainName, HyperlaneDeployer, - HyperlaneIgp, MultiProvider, } from '@hyperlane-xyz/sdk'; @@ -16,7 +15,7 @@ export class TestQuerySenderDeployer extends HyperlaneDeployer< TestQuerySenderConfig, typeof TEST_QUERY_SENDER_FACTORIES > { - constructor(multiProvider: MultiProvider, protected igp: HyperlaneIgp) { + constructor(multiProvider: MultiProvider) { super(multiProvider, TEST_QUERY_SENDER_FACTORIES); } @@ -25,10 +24,7 @@ export class TestQuerySenderDeployer extends HyperlaneDeployer< chain, 'TestQuerySender', [], - [ - config.queryRouterAddress, - this.igp.getContracts(chain).interchainGasPaymaster.address, - ], + [config.queryRouterAddress], ); return { TestQuerySender, diff --git a/typescript/sdk/.eslintrc b/typescript/sdk/.eslintrc index eb1e08414..54d42620e 100644 --- a/typescript/sdk/.eslintrc +++ b/typescript/sdk/.eslintrc @@ -1,5 +1,5 @@ { "rules": { - "@typescript-eslint/explicit-module-boundary-types": ["error"] + "@typescript-eslint/explicit-module-boundary-types": ["warn"] } } diff --git a/typescript/sdk/package.json b/typescript/sdk/package.json index c90e13e84..ff6df4593 100644 --- a/typescript/sdk/package.json +++ b/typescript/sdk/package.json @@ -5,6 +5,7 @@ "dependencies": { "@hyperlane-xyz/core": "1.5.0", "@hyperlane-xyz/utils": "1.5.0", + "@solana/spl-token": "^0.3.8", "@solana/web3.js": "^1.78.0", "@types/coingecko-api": "^1.0.10", "@types/debug": "^4.1.7", diff --git a/typescript/sdk/src/core/HyperlaneCore.ts b/typescript/sdk/src/core/HyperlaneCore.ts index 8f123bb88..c194e534f 100644 --- a/typescript/sdk/src/core/HyperlaneCore.ts +++ b/typescript/sdk/src/core/HyperlaneCore.ts @@ -1,7 +1,14 @@ import { ethers } from 'ethers'; import { Mailbox__factory } from '@hyperlane-xyz/core'; -import { messageId, parseMessage, pollAsync } from '@hyperlane-xyz/utils'; +import { + Address, + AddressBytes32, + messageId, + objMap, + parseMessage, + pollAsync, +} from '@hyperlane-xyz/utils'; import { HyperlaneApp } from '../app/HyperlaneApp'; import { @@ -11,7 +18,8 @@ import { import { appFromAddressesMapHelper } from '../contracts/contracts'; import { HyperlaneAddressesMap } from '../contracts/types'; import { MultiProvider } from '../providers/MultiProvider'; -import { ChainName } from '../types'; +import { RouterConfig } from '../router/types'; +import { ChainMap, ChainName } from '../types'; import { CoreFactories, coreFactories } from './contracts'; import { DispatchedMessage } from './types'; @@ -40,6 +48,26 @@ export class HyperlaneCore extends HyperlaneApp { return new HyperlaneCore(helper.contractsMap, helper.multiProvider); } + getRouterConfig = (owner: Address): ChainMap => + objMap(this.contractsMap, (_, contracts) => { + return { + mailbox: contracts.mailbox.address, + owner, + }; + }); + + quoteGasPayment = ( + origin: ChainName, + destination: ChainName, + recipient: AddressBytes32, + body: string, + ): Promise => { + const destinationId = this.multiProvider.getDomainId(destination); + return this.contractsMap[origin].mailbox[ + 'quoteDispatch(uint32,bytes32,bytes)' + ](destinationId, recipient, body); + }; + protected getDestination(message: DispatchedMessage): ChainName { return this.multiProvider.getChainName(message.parsed.destination); } diff --git a/typescript/sdk/src/deploy/HyperlaneDeployer.ts b/typescript/sdk/src/deploy/HyperlaneDeployer.ts index fbb10cac0..86aa9177d 100644 --- a/typescript/sdk/src/deploy/HyperlaneDeployer.ts +++ b/typescript/sdk/src/deploy/HyperlaneDeployer.ts @@ -2,8 +2,8 @@ import { Debugger, debug } from 'debug'; import { Contract, ethers } from 'ethers'; import { - HyperlaneConnectionClient, Mailbox, + MailboxClient, Mailbox__factory, Ownable, ProxyAdmin, @@ -26,7 +26,7 @@ import { moduleMatchesConfig, } from '../ism/HyperlaneIsmFactory'; import { MultiProvider } from '../providers/MultiProvider'; -import { ConnectionClientConfig } from '../router/types'; +import { MailboxClientConfig } from '../router/types'; import { ChainMap, ChainName } from '../types'; import { UpgradeConfig, proxyAdmin } from './proxy'; @@ -151,52 +151,36 @@ export abstract class HyperlaneDeployer< } } - protected async initConnectionClient( + protected async initMailboxClient( local: ChainName, - connectionClient: HyperlaneConnectionClient, - config: ConnectionClientConfig, + client: MailboxClient, + config: MailboxClientConfig, ): Promise { - this.logger( - `Initializing connection client (if not already) on ${local}...`, - ); - await this.runIfOwner(local, connectionClient, async () => { + this.logger(`Initializing mailbox client (if not already) on ${local}...`); + await this.runIfOwner(local, client, async () => { const txOverrides = this.multiProvider.getTransactionOverrides(local); - // set mailbox if not already set (and configured) - if (config.mailbox !== (await connectionClient.mailbox())) { - this.logger(`Set mailbox on (${local})`); - await this.multiProvider.handleTx( - local, - connectionClient.setMailbox(config.mailbox, txOverrides), - ); - } - // set interchain gas paymaster if not already set (and configured) - if ( - config.interchainGasPaymaster !== - (await connectionClient.interchainGasPaymaster()) - ) { - this.logger(`Set interchain gas paymaster on ${local}`); + // set hook if not already set (and configured) + if (config.hook && config.hook !== (await client.hook())) { + this.logger(`Set hook on ${local}`); await this.multiProvider.handleTx( local, - connectionClient.setInterchainGasPaymaster( - config.interchainGasPaymaster, - txOverrides, - ), + client.setHook(config.hook, txOverrides), ); } - let currentIsm = await connectionClient.interchainSecurityModule(); + let currentIsm = await client.interchainSecurityModule(); // in case the above returns zero address, fetch the defaultISM from the mailbox if (currentIsm === ethers.constants.AddressZero) { const mailbox: Mailbox = Mailbox__factory.connect( config.mailbox, - connectionClient.signer, + client.signer, ); currentIsm = await mailbox.defaultIsm(); } + // set interchain security module if not already set (and configured) if (config.interchainSecurityModule) { - // set interchain security module if not already set (and configured) let configuredIsm: string; if (typeof config.interchainSecurityModule === 'string') { configuredIsm = config.interchainSecurityModule; @@ -231,10 +215,7 @@ export abstract class HyperlaneDeployer< await this.multiProvider.handleTx( local, - connectionClient.setInterchainSecurityModule( - configuredIsm, - txOverrides, - ), + client.setInterchainSecurityModule(configuredIsm, txOverrides), ); } } diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index 2012bb805..7265be60c 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -60,7 +60,7 @@ export { TestCoreDeployer } from './core/TestCoreDeployer'; export { EvmCoreAdapter } from './core/adapters/EvmCoreAdapter'; export { SealevelCoreAdapter } from './core/adapters/SealevelCoreAdapter'; export { ICoreAdapter } from './core/adapters/types'; -export { CoreFactories, coreFactories, CoreAddresses } from './core/contracts'; +export { CoreAddresses, CoreFactories, coreFactories } from './core/contracts'; export { HyperlaneLifecyleEvent } from './core/events'; export { CoreConfig, @@ -125,8 +125,8 @@ export { DeployedIsm, IsmConfig, ModuleType, - MultisigIsmConfig, MultisigConfig, + MultisigIsmConfig, RoutingIsmConfig, } from './ism/types'; export { @@ -250,12 +250,12 @@ export { } from './router/adapters/SealevelRouterAdapter'; export { IGasRouterAdapter, IRouterAdapter } from './router/adapters/types'; export { - ConnectionClientConfig, - ConnectionClientViolation, - ConnectionClientViolationType, + ClientViolation as ConnectionClientViolation, + ClientViolationType as ConnectionClientViolationType, ForeignDeploymentConfig, GasConfig, GasRouterConfig, + MailboxClientConfig, OwnableConfig, ProxiedFactories, ProxiedRouterConfig, @@ -264,9 +264,57 @@ export { proxiedFactories, } from './router/types'; export { - createRouterConfigMap, - deployTestIgpsAndGetRouterConfig, -} from './test/testUtils'; + EvmHypCollateralAdapter, + EvmHypSyntheticAdapter, + EvmNativeTokenAdapter, + EvmTokenAdapter, +} from './token/adapters/EvmTokenAdapter'; +export { + IHypTokenAdapter, + ITokenAdapter, + TransferParams, + TransferRemoteParams, +} from './token/adapters/ITokenAdapter'; +export { + SealevelHypCollateralAdapter, + SealevelHypNativeAdapter, + SealevelHypSyntheticAdapter, + SealevelHypTokenAdapter, + SealevelNativeTokenAdapter, + SealevelTokenAdapter, +} from './token/adapters/SealevelTokenAdapter'; +export { + SealevelHypTokenInstruction, + SealevelHyperlaneTokenData, + SealevelHyperlaneTokenDataSchema, + SealevelTransferRemoteInstruction, + SealevelTransferRemoteSchema, +} from './token/adapters/serialization'; +export { + CollateralConfig, + ERC20Metadata, + ERC20RouterConfig, + ERC721RouterConfig, + HypERC20CollateralConfig, + HypERC20Config, + HypERC721CollateralConfig, + HypERC721Config, + HypNativeConfig, + MinimalTokenMetadata, + NativeConfig, + SyntheticConfig, + TokenConfig, + TokenMetadata, + TokenType, + isCollateralConfig, + isUriConfig, +} from './token/config'; +export { + HypERC20Factories, + HypERC721Factories, + TokenFactories, +} from './token/contracts'; +export { HypERC20Deployer, HypERC721Deployer } from './token/deploy'; export { ChainMap, ChainName, diff --git a/typescript/sdk/src/middleware/account/InterchainAccountDeployer.ts b/typescript/sdk/src/middleware/account/InterchainAccountDeployer.ts index 4c5b518d5..f564342de 100644 --- a/typescript/sdk/src/middleware/account/InterchainAccountDeployer.ts +++ b/typescript/sdk/src/middleware/account/InterchainAccountDeployer.ts @@ -24,30 +24,18 @@ export class InterchainAccountDeployer extends ProxiedRouterDeployer< super(multiProvider, interchainAccountFactories); } - async constructorArgs(chain: string, __: RouterConfig): Promise<[number]> { - const localDomain = this.multiProvider.getDomainId(chain); - return [localDomain]; + async constructorArgs(_: string, config: RouterConfig): Promise<[string]> { + return [config.mailbox]; } async initializeArgs( chain: string, config: RouterConfig, - ): Promise< - [ - _mailbox: string, - _interchainGasPaymaster: string, - _interchainSecurityModule: string, - _owner: string, - ] - > { + ): Promise<[string, string, string]> { const owner = await this.multiProvider.getSignerAddress(chain); - if (typeof config.interchainSecurityModule === 'object') { - throw new Error('ISM as object unimplemented'); - } return [ - config.mailbox, - config.interchainGasPaymaster, - config.interchainSecurityModule ?? ethers.constants.AddressZero, + config.hook ?? ethers.constants.AddressZero, + config.interchainSecurityModule! as string, // deployed in deployContracts owner, ]; } diff --git a/typescript/sdk/src/middleware/account/accounts.hardhat-test.ts b/typescript/sdk/src/middleware/account/accounts.hardhat-test.ts index fae93bbc8..1984dc7bd 100644 --- a/typescript/sdk/src/middleware/account/accounts.hardhat-test.ts +++ b/typescript/sdk/src/middleware/account/accounts.hardhat-test.ts @@ -13,7 +13,6 @@ import { TestCoreApp } from '../../core/TestCoreApp'; import { TestCoreDeployer } from '../../core/TestCoreDeployer'; import { MultiProvider } from '../../providers/MultiProvider'; import { RouterConfig } from '../../router/types'; -import { deployTestIgpsAndGetRouterConfig } from '../../test/testUtils'; import { ChainMap } from '../../types'; import { InterchainAccount } from './InterchainAccount'; @@ -35,20 +34,15 @@ describe.skip('InterchainAccounts', async () => { before(async () => { [signer] = await ethers.getSigners(); - multiProvider = MultiProvider.createTestMultiProvider({ signer }); - coreApp = await new TestCoreDeployer(multiProvider).deployApp(); - config = await deployTestIgpsAndGetRouterConfig( - multiProvider, - signer.address, - coreApp.contractsMap, - ); + config = coreApp.getRouterConfig(signer.address); }); beforeEach(async () => { - const deployer = new InterchainAccountDeployer(multiProvider); - contracts = await deployer.deploy(config); + contracts = await new InterchainAccountDeployer(multiProvider).deploy( + config, + ); local = contracts[localChain].interchainAccountRouter; remote = contracts[remoteChain].interchainAccountRouter; }); diff --git a/typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts b/typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts index d53aad9cf..6e338f116 100644 --- a/typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts +++ b/typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerRouterDeployer.ts @@ -61,28 +61,23 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< super(multiProvider, liquidityLayerFactories); } - async constructorArgs(_: string, __: LiquidityLayerConfig): Promise<[]> { - return []; + async constructorArgs( + _: string, + config: LiquidityLayerConfig, + ): Promise<[string]> { + return [config.mailbox]; } async initializeArgs( chain: string, config: LiquidityLayerConfig, - ): Promise< - [ - _mailbox: string, - _interchainGasPaymaster: string, - _interchainSecurityModule: string, - _owner: string, - ] - > { + ): Promise<[string, string, string]> { const owner = await this.multiProvider.getSignerAddress(chain); if (typeof config.interchainSecurityModule === 'object') { throw new Error('ISM as object unimplemented'); } return [ - config.mailbox, - config.interchainGasPaymaster, + config.hook ?? ethers.constants.AddressZero, config.interchainSecurityModule ?? ethers.constants.AddressZero, owner, ]; @@ -175,16 +170,12 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< owner: string, router: LiquidityLayerRouter, ): Promise { + const mailbox = await router.mailbox(); const portalAdapter = await this.deployContract( chain, 'portalAdapter', - [], - [ - this.multiProvider.getDomainId(chain), - owner, - adapterConfig.portalBridgeAddress, - router.address, - ], + [mailbox], + [owner, adapterConfig.portalBridgeAddress, router.address], ); for (const { @@ -233,10 +224,11 @@ export class LiquidityLayerDeployer extends ProxiedRouterDeployer< owner: string, router: LiquidityLayerRouter, ): Promise { + const mailbox = await router.mailbox(); const circleBridgeAdapter = await this.deployContract( chain, 'circleBridgeAdapter', - [], + [mailbox], [ owner, adapterConfig.tokenMessengerAddress, diff --git a/typescript/sdk/src/middleware/liquidity-layer/liquidity-layer.hardhat-test.ts b/typescript/sdk/src/middleware/liquidity-layer/liquidity-layer.hardhat-test.ts index d1ae0d9c0..14530723e 100644 --- a/typescript/sdk/src/middleware/liquidity-layer/liquidity-layer.hardhat-test.ts +++ b/typescript/sdk/src/middleware/liquidity-layer/liquidity-layer.hardhat-test.ts @@ -21,7 +21,6 @@ import { Chains } from '../../consts/chains'; import { TestCoreApp } from '../../core/TestCoreApp'; import { TestCoreDeployer } from '../../core/TestCoreDeployer'; import { MultiProvider } from '../../providers/MultiProvider'; -import { deployTestIgpsAndGetRouterConfig } from '../../test/testUtils'; import { ChainMap } from '../../types'; import { LiquidityLayerApp } from './LiquidityLayerApp'; @@ -53,12 +52,9 @@ describe.skip('LiquidityLayerRouter', async () => { before(async () => { [signer] = await ethers.getSigners(); - multiProvider = MultiProvider.createTestMultiProvider({ signer }); - - const coreDeployer = new TestCoreDeployer(multiProvider); - const coreContractsMaps = await coreDeployer.deploy(); - coreApp = new TestCoreApp(coreContractsMaps, multiProvider); + coreApp = await new TestCoreDeployer(multiProvider).deployApp(); + const routerConfig = coreApp.getRouterConfig(signer.address); const mockTokenF = new MockToken__factory(signer); mockToken = await mockTokenF.deploy(); @@ -72,11 +68,7 @@ describe.skip('LiquidityLayerRouter', async () => { signer, ); messageTransmitter = await messageTransmitterF.deploy(mockToken.address); - const routerConfig = await deployTestIgpsAndGetRouterConfig( - multiProvider, - signer.address, - coreContractsMaps, - ); + config = objMap(routerConfig, (chain, config) => { return { ...config, diff --git a/typescript/sdk/src/middleware/query/InterchainQueryDeployer.ts b/typescript/sdk/src/middleware/query/InterchainQueryDeployer.ts index e428bbdbc..588890c33 100644 --- a/typescript/sdk/src/middleware/query/InterchainQueryDeployer.ts +++ b/typescript/sdk/src/middleware/query/InterchainQueryDeployer.ts @@ -22,27 +22,20 @@ export class InterchainQueryDeployer extends ProxiedRouterDeployer< super(multiProvider, interchainQueryFactories); } - async constructorArgs(_: string, __: RouterConfig): Promise<[]> { - return []; + async constructorArgs(_: string, config: RouterConfig): Promise<[string]> { + return [config.mailbox]; } + async initializeArgs( chain: string, config: RouterConfig, - ): Promise< - [ - _mailbox: string, - _interchainGasPaymaster: string, - _interchainSecurityModule: string, - _owner: string, - ] - > { + ): Promise<[string, string, string]> { const owner = await this.multiProvider.getSignerAddress(chain); if (typeof config.interchainSecurityModule === 'object') { throw new Error('ISM as object unimplemented'); } return [ - config.mailbox, - config.interchainGasPaymaster, + config.hook ?? ethers.constants.AddressZero, config.interchainSecurityModule ?? ethers.constants.AddressZero, owner, ]; diff --git a/typescript/sdk/src/middleware/query/queries.hardhat-test.ts b/typescript/sdk/src/middleware/query/queries.hardhat-test.ts index db6b23ab1..6a64b004f 100644 --- a/typescript/sdk/src/middleware/query/queries.hardhat-test.ts +++ b/typescript/sdk/src/middleware/query/queries.hardhat-test.ts @@ -16,7 +16,6 @@ import { TestCoreApp } from '../../core/TestCoreApp'; import { TestCoreDeployer } from '../../core/TestCoreDeployer'; import { MultiProvider } from '../../providers/MultiProvider'; import { RouterConfig } from '../../router/types'; -import { deployTestIgpsAndGetRouterConfig } from '../../test/testUtils'; import { ChainMap } from '../../types'; import { InterchainQuery } from './InterchainQuery'; @@ -41,27 +40,15 @@ describe.skip('InterchainQueryRouter', async () => { before(async () => { [signer] = await ethers.getSigners(); - multiProvider = MultiProvider.createTestMultiProvider({ signer }); - - const coreDeployer = new TestCoreDeployer(multiProvider); - const coreContractsMaps = await coreDeployer.deploy(); - coreApp = new TestCoreApp(coreContractsMaps, multiProvider); - config = await deployTestIgpsAndGetRouterConfig( - multiProvider, - signer.address, - coreContractsMaps, - ); + coreApp = await new TestCoreDeployer(multiProvider).deployApp(); + config = coreApp.getRouterConfig(signer.address); }); beforeEach(async () => { - const InterchainQuery = new InterchainQueryDeployer(multiProvider); - - contracts = await InterchainQuery.deploy(config); - + contracts = await new InterchainQueryDeployer(multiProvider).deploy(config); local = contracts[localChain].interchainQueryRouter; remote = contracts[remoteChain].interchainQueryRouter; - testQuery = await new TestQuery__factory(signer).deploy(local.address); }); diff --git a/typescript/sdk/src/router/GasRouterDeployer.ts b/typescript/sdk/src/router/GasRouterDeployer.ts index d8b7122ac..a219c36e7 100644 --- a/typescript/sdk/src/router/GasRouterDeployer.ts +++ b/typescript/sdk/src/router/GasRouterDeployer.ts @@ -48,7 +48,9 @@ export abstract class GasRouterDeployer< this.logger(`Set destination gas on ${chain} for ${remoteChains}`); await this.multiProvider.handleTx( chain, - this.router(contracts).setDestinationGas(remoteConfigs), + this.router(contracts)['setDestinationGas((uint32,uint256)[])']( + remoteConfigs, + ), ); } } diff --git a/typescript/sdk/src/router/HyperlaneRouterChecker.ts b/typescript/sdk/src/router/HyperlaneRouterChecker.ts index 442ac1183..512d46890 100644 --- a/typescript/sdk/src/router/HyperlaneRouterChecker.ts +++ b/typescript/sdk/src/router/HyperlaneRouterChecker.ts @@ -8,9 +8,9 @@ import { ChainName } from '../types'; import { RouterApp } from './RouterApps'; import { - ConnectionClientConfig, - ConnectionClientViolation, - ConnectionClientViolationType, + ClientViolation, + ClientViolationType, + MailboxClientConfig, OwnableConfig, RouterConfig, } from './types'; @@ -21,29 +21,29 @@ export class HyperlaneRouterChecker< Config extends RouterConfig, > extends HyperlaneAppChecker { async checkChain(chain: ChainName): Promise { - await this.checkHyperlaneConnectionClient(chain); + await this.checkMailboxClient(chain); await this.checkEnrolledRouters(chain); await super.checkOwnership(chain, this.configMap[chain].owner); } - async checkHyperlaneConnectionClient(chain: ChainName): Promise { + async checkMailboxClient(chain: ChainName): Promise { const router = this.app.router(this.app.getContracts(chain)); - const checkConnectionClientProperty = async ( - property: keyof (ConnectionClientConfig & OwnableConfig), - violationType: ConnectionClientViolationType, + const checkMailboxClientProperty = async ( + property: keyof (MailboxClientConfig & OwnableConfig), + violationType: ClientViolationType, ) => { const actual = await router[property](); // TODO: check for IsmConfig const value = this.configMap[chain][property]; if (value && typeof value === 'object') - throw new Error('ISM as object unimplemented'); + throw new Error('object config unimplemented'); const expected = value && typeof value === 'string' ? value : ethers.constants.AddressZero; if (!eqAddress(actual, expected)) { - const violation: ConnectionClientViolation = { + const violation: ClientViolation = { chain, type: violationType, contract: router, @@ -54,17 +54,11 @@ export class HyperlaneRouterChecker< } }; - await checkConnectionClientProperty( - 'mailbox', - ConnectionClientViolationType.Mailbox, - ); - await checkConnectionClientProperty( - 'interchainGasPaymaster', - ConnectionClientViolationType.InterchainGasPaymaster, - ); - await checkConnectionClientProperty( + await checkMailboxClientProperty('mailbox', ClientViolationType.Mailbox); + await checkMailboxClientProperty('hook', ClientViolationType.Hook); + await checkMailboxClientProperty( 'interchainSecurityModule', - ConnectionClientViolationType.InterchainSecurityModule, + ClientViolationType.Hook, ); } diff --git a/typescript/sdk/src/router/HyperlaneRouterDeployer.ts b/typescript/sdk/src/router/HyperlaneRouterDeployer.ts index 4fa5b6c3e..403272a26 100644 --- a/typescript/sdk/src/router/HyperlaneRouterDeployer.ts +++ b/typescript/sdk/src/router/HyperlaneRouterDeployer.ts @@ -1,13 +1,12 @@ -import { ethers } from 'ethers'; - import { - IInterchainGasPaymaster__factory, + IPostDispatchHook__factory, Mailbox__factory, Router, } from '@hyperlane-xyz/core'; import { Address, addressToBytes32, + formatMessage, objFilter, objMap, objMerge, @@ -37,41 +36,47 @@ export abstract class HyperlaneRouterDeployer< for (const [local, config] of Object.entries(configMap)) { this.logger(`Checking config for ${local}...`); const signerOrProvider = this.multiProvider.getSignerOrProvider(local); - const localIgp = IInterchainGasPaymaster__factory.connect( - config.interchainGasPaymaster, - signerOrProvider, - ); const localMailbox = Mailbox__factory.connect( config.mailbox, signerOrProvider, ); - let localIsm; - if ( - !config.interchainSecurityModule || - config.interchainSecurityModule === ethers.constants.AddressZero - ) { - localIsm = await localMailbox.defaultIsm(); - } else { - localIsm = config.interchainSecurityModule; - } + + const localHook = IPostDispatchHook__factory.connect( + config.hook ?? (await localMailbox.defaultHook()), + signerOrProvider, + ); + + const deployer = await this.multiProvider.getSignerAddress(local); const remotes = Object.keys(configMap).filter((c) => c !== local); for (const remote of remotes) { - this.logger(`Checking origin ${remote}...`); - // Try to confirm that the IGP supports delivery to all remotes + const origin = this.multiProvider.getDomainId(local); + const destination = this.multiProvider.getDomainId(remote); + const message = formatMessage( + 0, + 0, + origin, + deployer, + destination, + deployer, + '', + ); + + // Try to confirm that the hook supports delivery to all remotes + this.logger(`Checking ${local} => ${remote} hook...`); try { - await localIgp.quoteGasPayment( - this.multiProvider.getDomainId(remote), - 1, - ); + await localHook.quoteDispatch('', message); } catch (e) { throw new Error( - `The specified or default IGP with address ${localIgp.address} on ` + + `The specified or default hook with address ${localHook.address} on ` + `${local} is not configured to deliver messages to ${remote}, ` + `did you mean to specify a different one?`, ); } + const localIsm = + config.interchainSecurityModule ?? (await localMailbox.defaultIsm()); + // Try to confirm that the specified or default ISM can verify messages to all remotes const canVerify = await moduleCanCertainlyVerify( localIsm, @@ -80,8 +85,9 @@ export abstract class HyperlaneRouterDeployer< local, ); if (!canVerify) { + const ismString = JSON.stringify(localIsm); throw new Error( - `The specified or default ISM with address ${localIsm} on ${local} ` + + `The specified or default ISM ${ismString} on ${local} ` + `cannot verify messages from ${remote}, did you forget to ` + `specify an ISM, or mean to specify a different one?`, ); @@ -90,14 +96,14 @@ export abstract class HyperlaneRouterDeployer< } } - async initConnectionClients( + async initMailboxClients( contractsMap: HyperlaneContractsMap, configMap: ChainMap, ): Promise { for (const chain of Object.keys(contractsMap)) { const contracts = contractsMap[chain]; const config = configMap[chain]; - await super.initConnectionClient(chain, this.router(contracts), config); + await super.initMailboxClient(chain, this.router(contracts), config); } } @@ -198,7 +204,7 @@ export abstract class HyperlaneRouterDeployer< configMap, foreignDeployments, ); - await this.initConnectionClients(deployedContractsMap, configMap); + await this.initMailboxClients(deployedContractsMap, configMap); await this.transferOwnership(deployedContractsMap, configMap); this.logger(`Finished deploying router contracts for all chains.`); diff --git a/typescript/sdk/src/router/ProxiedRouterChecker.ts b/typescript/sdk/src/router/ProxiedRouterChecker.ts index 88545c671..560a90bd7 100644 --- a/typescript/sdk/src/router/ProxiedRouterChecker.ts +++ b/typescript/sdk/src/router/ProxiedRouterChecker.ts @@ -22,7 +22,7 @@ export abstract class ProxiedRouterChecker< } async checkChain(chain: ChainName): Promise { - await super.checkHyperlaneConnectionClient(chain); + await super.checkMailboxClient(chain); await super.checkEnrolledRouters(chain); await this.checkProxiedContracts(chain); await this.checkOwnership(chain); diff --git a/typescript/sdk/src/router/types.ts b/typescript/sdk/src/router/types.ts index 9a56f06d4..5a6cfaf88 100644 --- a/typescript/sdk/src/router/types.ts +++ b/typescript/sdk/src/router/types.ts @@ -1,5 +1,5 @@ import { - HyperlaneConnectionClient, + MailboxClient, ProxyAdmin__factory, TimelockController__factory, } from '@hyperlane-xyz/core'; @@ -22,7 +22,7 @@ export type ForeignDeploymentConfig = { foreignDeployment?: Address; }; -export type RouterConfig = ConnectionClientConfig & +export type RouterConfig = MailboxClientConfig & OwnableConfig & ForeignDeploymentConfig; @@ -44,21 +44,24 @@ export const proxiedFactories: ProxiedFactories = { timelockController: new TimelockController__factory(), }; -export type ConnectionClientConfig = { +// TODO: merge with kunal's hook deployer +type HookConfig = Address; + +export type MailboxClientConfig = { mailbox: Address; - interchainGasPaymaster: Address; - interchainSecurityModule?: Address | IsmConfig; + hook?: HookConfig; + interchainSecurityModule?: IsmConfig; }; -export enum ConnectionClientViolationType { - InterchainSecurityModule = 'ConnectionClientIsm', - Mailbox = 'ConnectionClientMailbox', - InterchainGasPaymaster = 'ConnectionClientIgp', +export enum ClientViolationType { + InterchainSecurityModule = 'ClientIsm', + Mailbox = 'ClientMailbox', + Hook = 'ClientHook', } -export interface ConnectionClientViolation extends CheckerViolation { - type: ConnectionClientViolationType; - contract: HyperlaneConnectionClient; +export interface ClientViolation extends CheckerViolation { + type: ClientViolationType; + contract: MailboxClient; actual: string; expected: string; } diff --git a/typescript/sdk/src/test/testUtils.ts b/typescript/sdk/src/test/testUtils.ts index d4b5ac8c6..482b7a200 100644 --- a/typescript/sdk/src/test/testUtils.ts +++ b/typescript/sdk/src/test/testUtils.ts @@ -1,9 +1,5 @@ import { ethers } from 'ethers'; -import { - TestInterchainGasPaymaster, - TestInterchainGasPaymaster__factory, -} from '@hyperlane-xyz/core'; import { Address, objMap } from '@hyperlane-xyz/utils'; import { chainMetadata } from '../consts/chainMetadata'; @@ -18,7 +14,6 @@ import { CoinGeckoSimplePriceParams, } from '../gas/token-prices'; import { ModuleType, MultisigIsmConfig } from '../ism/types'; -import { MultiProvider } from '../providers/MultiProvider'; import { RouterConfig } from '../router/types'; import { ChainMap, ChainName } from '../types'; @@ -45,27 +40,6 @@ export function createRouterConfigMap( }); } -export async function deployTestIgpsAndGetRouterConfig( - multiProvider: MultiProvider, - owner: Address, - coreContracts: HyperlaneContractsMap, -): Promise> { - const igps: ChainMap = {}; - for (const chain of multiProvider.getKnownChainNames()) { - const factory = new TestInterchainGasPaymaster__factory( - multiProvider.getSigner(chain), - ); - igps[chain] = await factory.deploy(); - } - return objMap(coreContracts, (chain, contracts) => { - return { - owner, - mailbox: contracts.mailbox.address, - interchainGasPaymaster: igps[chain].address, - }; - }); -} - const nonZeroAddress = ethers.constants.AddressZero.replace('00', '01'); // dummy config as TestInbox and TestOutbox do not use deployed ISM diff --git a/typescript/token/src/adapters/EvmTokenAdapter.ts b/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts similarity index 96% rename from typescript/token/src/adapters/EvmTokenAdapter.ts rename to typescript/sdk/src/token/adapters/EvmTokenAdapter.ts index d2ab16754..338c48437 100644 --- a/typescript/token/src/adapters/EvmTokenAdapter.ts +++ b/typescript/sdk/src/token/adapters/EvmTokenAdapter.ts @@ -1,10 +1,12 @@ import { BigNumber, PopulatedTransaction } from 'ethers'; import { - BaseEvmAdapter, - ChainName, - MultiProtocolProvider, -} from '@hyperlane-xyz/sdk'; + ERC20, + ERC20__factory, + HypERC20, + HypERC20Collateral__factory, + HypERC20__factory, +} from '@hyperlane-xyz/core'; import { Address, Domain, @@ -14,14 +16,10 @@ import { strip0x, } from '@hyperlane-xyz/utils'; +import { BaseEvmAdapter } from '../../app/MultiProtocolApp'; +import { MultiProtocolProvider } from '../../providers/MultiProtocolProvider'; +import { ChainName } from '../../types'; import { MinimalTokenMetadata } from '../config'; -import { - ERC20, - ERC20__factory, - HypERC20, - HypERC20Collateral__factory, - HypERC20__factory, -} from '../types'; import { IHypTokenAdapter, diff --git a/typescript/token/src/adapters/ITokenAdapter.ts b/typescript/sdk/src/token/adapters/ITokenAdapter.ts similarity index 100% rename from typescript/token/src/adapters/ITokenAdapter.ts rename to typescript/sdk/src/token/adapters/ITokenAdapter.ts diff --git a/typescript/token/src/adapters/SealevelTokenAdapter.ts b/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts similarity index 97% rename from typescript/token/src/adapters/SealevelTokenAdapter.ts rename to typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts index f88758d0b..91b3b1745 100644 --- a/typescript/token/src/adapters/SealevelTokenAdapter.ts +++ b/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts @@ -15,16 +15,6 @@ import { import BigNumber from 'bignumber.js'; import { deserializeUnchecked, serialize } from 'borsh'; -import { - BaseSealevelAdapter, - ChainName, - MultiProtocolProvider, - SEALEVEL_SPL_NOOP_ADDRESS, - SealevelAccountDataWrapper, - SealevelInstructionWrapper, - SealevelInterchainGasPaymasterType, - SealevelOverheadIgpAdapter, -} from '@hyperlane-xyz/sdk'; import { Address, Domain, @@ -33,6 +23,16 @@ import { isZeroishAddress, } from '@hyperlane-xyz/utils'; +import { BaseSealevelAdapter } from '../../app/MultiProtocolApp'; +import { SEALEVEL_SPL_NOOP_ADDRESS } from '../../consts/sealevel'; +import { SealevelOverheadIgpAdapter } from '../../gas/adapters/SealevelIgpAdapter'; +import { SealevelInterchainGasPaymasterType } from '../../gas/adapters/serialization'; +import { MultiProtocolProvider } from '../../providers/MultiProtocolProvider'; +import { ChainName } from '../../types'; +import { + SealevelAccountDataWrapper, + SealevelInstructionWrapper, +} from '../../utils/sealevelSerialization'; import { MinimalTokenMetadata } from '../config'; import { diff --git a/typescript/token/src/adapters/serialization.ts b/typescript/sdk/src/token/adapters/serialization.ts similarity index 98% rename from typescript/token/src/adapters/serialization.ts rename to typescript/sdk/src/token/adapters/serialization.ts index 8ff30424d..822ab5b3f 100644 --- a/typescript/token/src/adapters/serialization.ts +++ b/typescript/sdk/src/token/adapters/serialization.ts @@ -1,13 +1,16 @@ import { PublicKey } from '@solana/web3.js'; +import { Domain } from '@hyperlane-xyz/utils'; + import { - SealevelAccountDataWrapper, - SealevelInstructionWrapper, SealevelInterchainGasPaymasterConfig, SealevelInterchainGasPaymasterConfigSchema, +} from '../../gas/adapters/serialization'; +import { + SealevelAccountDataWrapper, + SealevelInstructionWrapper, getSealevelAccountDataSchema, -} from '@hyperlane-xyz/sdk'; -import { Domain } from '@hyperlane-xyz/utils'; +} from '../../utils/sealevelSerialization'; /** * Hyperlane Token Borsh Schema diff --git a/typescript/token/src/config.ts b/typescript/sdk/src/token/config.ts similarity index 97% rename from typescript/token/src/config.ts rename to typescript/sdk/src/token/config.ts index 6212ca5ea..6772cda27 100644 --- a/typescript/token/src/config.ts +++ b/typescript/sdk/src/token/config.ts @@ -1,6 +1,6 @@ import { ethers } from 'ethers'; -import { GasRouterConfig } from '@hyperlane-xyz/sdk'; +import { GasRouterConfig } from '../router/types'; export enum TokenType { synthetic = 'synthetic', diff --git a/typescript/token/src/contracts.ts b/typescript/sdk/src/token/contracts.ts similarity index 94% rename from typescript/token/src/contracts.ts rename to typescript/sdk/src/token/contracts.ts index e22cc49a0..9cbf36614 100644 --- a/typescript/token/src/contracts.ts +++ b/typescript/sdk/src/token/contracts.ts @@ -5,7 +5,7 @@ import { HypERC721URICollateral__factory, HypERC721__factory, HypNative__factory, -} from './types'; +} from '@hyperlane-xyz/core'; export type HypERC20Factories = { router: HypERC20__factory | HypERC20Collateral__factory | HypNative__factory; diff --git a/typescript/token/src/deploy.ts b/typescript/sdk/src/token/deploy.ts similarity index 91% rename from typescript/token/src/deploy.ts rename to typescript/sdk/src/token/deploy.ts index 275d8d9d8..4e05305d4 100644 --- a/typescript/token/src/deploy.ts +++ b/typescript/sdk/src/token/deploy.ts @@ -1,16 +1,30 @@ import { providers } from 'ethers'; import { - ChainMap, - ChainName, - GasConfig, - GasRouterDeployer, - HyperlaneContracts, - MultiProvider, - RouterConfig, -} from '@hyperlane-xyz/sdk'; + ERC20__factory, + ERC721EnumerableUpgradeable__factory, + HypERC20, + HypERC20Collateral, + HypERC20Collateral__factory, + HypERC20__factory, + HypERC721, + HypERC721Collateral, + HypERC721Collateral__factory, + HypERC721URICollateral__factory, + HypERC721URIStorage__factory, + HypERC721__factory, + HypNative, + HypNativeScaled__factory, + HypNative__factory, +} from '@hyperlane-xyz/core'; import { objMap } from '@hyperlane-xyz/utils'; +import { HyperlaneContracts } from '../contracts/types'; +import { MultiProvider } from '../providers/MultiProvider'; +import { GasRouterDeployer } from '../router/GasRouterDeployer'; +import { GasConfig, RouterConfig } from '../router/types'; +import { ChainMap, ChainName } from '../types'; + import { CollateralConfig, ERC20Metadata, @@ -31,23 +45,6 @@ import { isUriConfig, } from './config'; import { HypERC20Factories, HypERC721Factories } from './contracts'; -import { - ERC20__factory, - ERC721EnumerableUpgradeable__factory, - HypERC20, - HypERC20Collateral, - HypERC20Collateral__factory, - HypERC20__factory, - HypERC721, - HypERC721Collateral, - HypERC721Collateral__factory, - HypERC721URICollateral__factory, - HypERC721URIStorage__factory, - HypERC721__factory, - HypNative, - HypNativeScaled__factory, - HypNative__factory, -} from './types'; export class HypERC20Deployer extends GasRouterDeployer< ERC20RouterConfig, @@ -124,14 +121,12 @@ export class HypERC20Deployer extends GasRouterDeployer< chain: ChainName, config: HypERC20CollateralConfig, ): Promise { - const router = await this.deployContractFromFactory( + return this.deployContractFromFactory( chain, new HypERC20Collateral__factory(), 'HypERC20Collateral', - [config.token], + [config.token, config.mailbox], ); - await this.multiProvider.handleTx(chain, router.initialize(config.mailbox)); - return router; } protected async deployNative( @@ -144,17 +139,16 @@ export class HypERC20Deployer extends GasRouterDeployer< chain, new HypNativeScaled__factory(), 'HypNativeScaled', - [config.scale], + [config.scale, config.mailbox], ); } else { router = await this.deployContractFromFactory( chain, new HypNative__factory(), 'HypNative', - [], + [config.mailbox], ); } - await this.multiProvider.handleTx(chain, router.initialize(config.mailbox)); return router; } @@ -166,16 +160,11 @@ export class HypERC20Deployer extends GasRouterDeployer< chain, new HypERC20__factory(), 'HypERC20', - [config.decimals], + [config.decimals, config.mailbox], ); await this.multiProvider.handleTx( chain, - router.initialize( - config.mailbox, - config.totalSupply, - config.name, - config.symbol, - ), + router.initialize(config.totalSupply, config.name, config.symbol), ); return router; } @@ -306,17 +295,16 @@ export class HypERC721Deployer extends GasRouterDeployer< chain, new HypERC721URICollateral__factory(), 'HypERC721URICollateral', - [config.token], + [config.token, config.mailbox], ); } else { router = await this.deployContractFromFactory( chain, new HypERC721Collateral__factory(), 'HypERC721Collateral', - [config.token], + [config.token, config.mailbox], ); } - await this.multiProvider.handleTx(chain, router.initialize(config.mailbox)); return router; } @@ -330,24 +318,19 @@ export class HypERC721Deployer extends GasRouterDeployer< chain, new HypERC721URIStorage__factory(), 'HypERC721URIStorage', - [], + [config.mailbox], ); } else { router = await this.deployContractFromFactory( chain, new HypERC721__factory(), 'HypERC721', - [], + [config.mailbox], ); } await this.multiProvider.handleTx( chain, - router.initialize( - config.mailbox, - config.totalSupply, - config.name, - config.symbol, - ), + router.initialize(config.totalSupply, config.name, config.symbol), ); return router; } diff --git a/typescript/token/.eslintignore b/typescript/token/.eslintignore deleted file mode 100644 index d6c78b68a..000000000 --- a/typescript/token/.eslintignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules -dist -coverage -types -hardhat.config.ts -scripts -test diff --git a/typescript/token/.eslintrc b/typescript/token/.eslintrc deleted file mode 100644 index e3f712414..000000000 --- a/typescript/token/.eslintrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "no-console": ["off"] - } -} diff --git a/typescript/token/.gitignore b/typescript/token/.gitignore deleted file mode 100644 index 7935c8fca..000000000 --- a/typescript/token/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -node_modules/ -cache/ -artifacts/ -types/ -dist/ -coverage/ -coverage.json -*.swp -.yarn/install-state.gz -# foundry -docs -out diff --git a/typescript/token/.prettierignore b/typescript/token/.prettierignore deleted file mode 100644 index f305b5f7b..000000000 --- a/typescript/token/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -src/types -test/outputs diff --git a/typescript/token/.prettierrc b/typescript/token/.prettierrc deleted file mode 100644 index 7abcd19c9..000000000 --- a/typescript/token/.prettierrc +++ /dev/null @@ -1,21 +0,0 @@ -{ - "tabWidth": 2, - "singleQuote": true, - "trailingComma": "all", - "overrides": [ - { - "files": "*.sol", - "options": { - "printWidth": 80, - "tabWidth": 4, - "useTabs": false, - "singleQuote": false, - "bracketSpacing": false, - "explicitTypes": "always" - } - } - ], - "importOrder": ["^@hyperlane-xyz/(.*)$", "^../(.*)$", "^./(.*)$"], - "importOrderSeparation": true, - "importOrderSortSpecifiers": true -} diff --git a/typescript/token/.solcover.js b/typescript/token/.solcover.js deleted file mode 100644 index e06da7cac..000000000 --- a/typescript/token/.solcover.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - skipFiles: ['test'], -}; diff --git a/typescript/token/.solhint.json b/typescript/token/.solhint.json deleted file mode 100644 index 0a512e65b..000000000 --- a/typescript/token/.solhint.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "solhint:recommended", - "rules": { - "compiler-version": ["error", ">=0.6.0"], - "func-visibility": ["warn", {"ignoreConstructors":true}], - "not-rely-on-time": "off" - } -} diff --git a/typescript/token/LICENSE.md b/typescript/token/LICENSE.md deleted file mode 100644 index 5312f8215..000000000 --- a/typescript/token/LICENSE.md +++ /dev/null @@ -1,193 +0,0 @@ -# Apache License - -_Version 2.0, January 2004_ -_<>_ - -### Terms and Conditions for use, reproduction, and distribution - -#### 1. Definitions - -“License” shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -“Licensor” shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -“Legal Entity” shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, “control” means **(i)** the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the -outstanding shares, or **(iii)** beneficial ownership of such entity. - -“You” (or “Your”) shall mean an individual or Legal Entity exercising -permissions granted by this License. - -“Source” form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -“Object” form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -“Work” shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -“Derivative Works” shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -“Contribution” shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -“submitted” means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as “Not a Contribution.” - -“Contributor” shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -#### 2. Grant of Copyright License - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -#### 3. Grant of Patent License - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -#### 4. Redistribution - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -- **(a)** You must give any other recipients of the Work or Derivative Works a copy of - this License; and -- **(b)** You must cause any modified files to carry prominent notices stating that You - changed the files; and -- **(c)** You must retain, in the Source form of any Derivative Works that You distribute, - all copyright, patent, trademark, and attribution notices from the Source form - of the Work, excluding those notices that do not pertain to any part of the - Derivative Works; and -- **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any - Derivative Works that You distribute must include a readable copy of the - attribution notices contained within such NOTICE file, excluding those notices - that do not pertain to any part of the Derivative Works, in at least one of the - following places: within a NOTICE text file distributed as part of the - Derivative Works; within the Source form or documentation, if provided along - with the Derivative Works; or, within a display generated by the Derivative - Works, if and wherever such third-party notices normally appear. The contents of - the NOTICE file are for informational purposes only and do not modify the - License. You may add Your own attribution notices within Derivative Works that - You distribute, alongside or as an addendum to the NOTICE text from the Work, - provided that such additional attribution notices cannot be construed as - modifying the License. - -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -#### 5. Submission of Contributions - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -#### 6. Trademarks - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -#### 7. Disclaimer of Warranty - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -#### 8. Limitation of Liability - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -#### 9. Accepting Warranty or Additional Liability - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -_END OF TERMS AND CONDITIONS_ - -### APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets `[]` replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same “printed page” as the copyright notice for easier identification within -third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/typescript/token/configs/warp-route-chain-config.json b/typescript/token/configs/warp-route-chain-config.json deleted file mode 100644 index 3eb487e3e..000000000 --- a/typescript/token/configs/warp-route-chain-config.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "goerli": { - "chainId": 5, - "name": "goerli", - "displayName": "Goerli", - "nativeToken": { "name": "Ether", "symbol": "ETH", "decimals": 18 }, - "publicRpcUrls": [{ "http": "https://eth-goerli.public.blastapi.io" }], - "blockExplorers": [ - { - "name": "Goerliscan", - "url": "https://goerli.etherscan.io", - "apiUrl": "https://api-goerli.etherscan.io", - "family": "etherscan" - } - ], - "blocks": { - "confirmations": 1, - "reorgPeriod": 2, - "estimateBlockTime": 13 - } - } -} diff --git a/typescript/token/configs/warp-route-token-config.json b/typescript/token/configs/warp-route-token-config.json deleted file mode 100644 index a6569dccc..000000000 --- a/typescript/token/configs/warp-route-token-config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "goerli": { - "type": "collateral", - "token": "0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6", - "owner": "0x5bA371aeA18734Cb7195650aFdfCa4f9251aa513", - "mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685", - "interchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1" - }, - "alfajores": { - "type": "synthetic", - "owner": "0x5bA371aeA18734Cb7195650aFdfCa4f9251aa513", - "mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685", - "interchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1" - }, - "fuji": { - "type": "synthetic", - "owner": "0x5bA371aeA18734Cb7195650aFdfCa4f9251aa513", - "mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685", - "interchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1" - }, - "moonbasealpha": { - "type": "synthetic", - "owner": "0x5bA371aeA18734Cb7195650aFdfCa4f9251aa513", - "mailbox": "0xCC737a94FecaeC165AbCf12dED095BB13F037685", - "interchainGasPaymaster": "0xF90cB82a76492614D07B82a7658917f3aC811Ac1" - } -} diff --git a/typescript/token/foundry.toml b/typescript/token/foundry.toml deleted file mode 100644 index 9c895773e..000000000 --- a/typescript/token/foundry.toml +++ /dev/null @@ -1,10 +0,0 @@ -[profile.default] -src = "contracts" -out = "out" -libs = ["lib"] -allow_paths = ["../../node_modules", "../../solidity"] -solc = '0.8.15' -optimizer = true -optimizer_runs = 999_999 - -# See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/typescript/token/hardhat.config.ts b/typescript/token/hardhat.config.ts deleted file mode 100644 index 7c2e51c6f..000000000 --- a/typescript/token/hardhat.config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import '@nomiclabs/hardhat-ethers'; -import '@nomiclabs/hardhat-waffle'; -import '@typechain/hardhat'; -import 'hardhat-gas-reporter'; -import 'solidity-coverage'; - -/** - * @type import('hardhat/config').HardhatUserConfig - */ -module.exports = { - solidity: { - compilers: [ - { - version: '0.8.16', - }, - ], - }, - gasReporter: { - currency: 'USD', - }, - typechain: { - outDir: './src/types', - target: 'ethers-v5', - alwaysGenerateOverloads: false, // should overloads with full signatures like deposit(uint256) be generated always, even if there are no overloads? - }, -}; diff --git a/typescript/token/lib/forge-std b/typescript/token/lib/forge-std deleted file mode 160000 index 1d9650e95..000000000 --- a/typescript/token/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1d9650e951204a0ddce9ff89c32f1997984cef4d diff --git a/typescript/token/package.json b/typescript/token/package.json deleted file mode 100644 index 65fa9a32e..000000000 --- a/typescript/token/package.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "@hyperlane-xyz/hyperlane-token", - "description": "A template for interchain ERC20 and ERC721 tokens using Hyperlane", - "version": "1.5.0", - "dependencies": { - "@hyperlane-xyz/core": "1.5.0", - "@hyperlane-xyz/sdk": "1.5.0", - "@hyperlane-xyz/utils": "1.5.0", - "@openzeppelin/contracts-upgradeable": "^4.8.0", - "@solana/spl-token": "^0.3.8", - "ethers": "^5.7.2" - }, - "devDependencies": { - "@nomiclabs/hardhat-ethers": "^2.2.1", - "@nomiclabs/hardhat-waffle": "^2.0.3", - "@trivago/prettier-plugin-sort-imports": "^3.2.0", - "@typechain/ethers-v5": "10.0.0", - "@typechain/hardhat": "^6.0.0", - "@types/mocha": "^9.1.0", - "@typescript-eslint/eslint-plugin": "^5.62.0", - "@typescript-eslint/parser": "^5.62.0", - "chai": "^4.3.0", - "eslint": "^8.16.0", - "eslint-config-prettier": "^8.5.0", - "ethereum-waffle": "^3.4.4", - "hardhat": "^2.16.1", - "hardhat-gas-reporter": "^1.0.9", - "prettier": "^2.4.1", - "prettier-plugin-solidity": "^1.0.0-beta.5", - "solhint": "^3.3.2", - "solhint-plugin-prettier": "^0.0.5", - "solidity-coverage": "^0.8.3", - "ts-node": "^10.8.0", - "typechain": "8.0.0", - "typescript": "^5.1.6" - }, - "files": [ - "/dist", - "/contracts", - "/docs" - ], - "homepage": "https://www.hyperlane.xyz", - "keywords": [ - "Hyperlane", - "Solidity", - "Token" - ], - "license": "Apache-2.0", - "main": "dist/index.js", - "packageManager": "yarn@3.2.0", - "repository": { - "type": "git", - "url": "https://github.com/hyperlane-xyz/hyperlane-token" - }, - "scripts": { - "clean": "hardhat clean && rm -rf dist cache src/types && forge clean", - "docs": "forge doc", - "build": "forge build && hardhat compile && tsc", - "coverage": "forge coverage --report lcov", - "lint": "solhint contracts/**/*.sol && eslint . --ext .ts", - "prettier": "prettier --write ./contracts ./test", - "test": "forge test -vvv", - "deploy-warp-route": "DEBUG=* ts-node scripts/deploy" - }, - "types": "dist/index.d.ts" -} diff --git a/typescript/token/remappings.txt b/typescript/token/remappings.txt deleted file mode 100644 index 13cb3ed9e..000000000 --- a/typescript/token/remappings.txt +++ /dev/null @@ -1,3 +0,0 @@ -@openzeppelin=../../node_modules/@openzeppelin -@hyperlane-xyz=../../node_modules/@hyperlane-xyz -forge-std/=lib/forge-std/src/ diff --git a/typescript/token/src/index.ts b/typescript/token/src/index.ts deleted file mode 100644 index 3025af926..000000000 --- a/typescript/token/src/index.ts +++ /dev/null @@ -1,53 +0,0 @@ -export { - EvmHypCollateralAdapter, - EvmHypSyntheticAdapter, - EvmNativeTokenAdapter, - EvmTokenAdapter, -} from './adapters/EvmTokenAdapter'; -export { - IHypTokenAdapter, - ITokenAdapter, - TransferParams, - TransferRemoteParams, -} from './adapters/ITokenAdapter'; -export { - SealevelHypCollateralAdapter, - SealevelHypNativeAdapter, - SealevelHypSyntheticAdapter, - SealevelHypTokenAdapter, - SealevelNativeTokenAdapter, - SealevelTokenAdapter, -} from './adapters/SealevelTokenAdapter'; -export { - SealevelHypTokenInstruction, - SealevelHyperlaneTokenData, - SealevelHyperlaneTokenDataSchema, - SealevelTransferRemoteInstruction, - SealevelTransferRemoteSchema, -} from './adapters/serialization'; -export { - CollateralConfig, - ERC20Metadata, - ERC20RouterConfig, - ERC721RouterConfig, - HypERC20CollateralConfig, - HypERC20Config, - HypERC721CollateralConfig, - HypERC721Config, - HypNativeConfig, - MinimalTokenMetadata, - NativeConfig, - SyntheticConfig, - TokenConfig, - TokenMetadata, - TokenType, - isCollateralConfig, - isUriConfig, -} from './config'; -export { - HypERC20Factories, - HypERC721Factories, - TokenFactories, -} from './contracts'; -export { HypERC20Deployer, HypERC721Deployer } from './deploy'; -export * from './types'; diff --git a/typescript/token/tsconfig.json b/typescript/token/tsconfig.json deleted file mode 100644 index 18f5bb5bc..000000000 --- a/typescript/token/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist/", - "rootDir": "./src/" - }, - "exclude": [ - "./node_modules/", - "./scripts/", - "./test/", - "./dist/", - "./src/types/hardhat.d.ts", - "hardhat.config.ts" - ], -} diff --git a/yarn.lock b/yarn.lock index 4e0204e2f..11b095c0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2637,11 +2637,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.22.6": - version: 7.22.10 - resolution: "@babel/runtime@npm:7.22.10" + version: 7.23.1 + resolution: "@babel/runtime@npm:7.23.1" dependencies: regenerator-runtime: ^0.14.0 - checksum: 524d41517e68953dbc73a4f3616b8475e5813f64e28ba89ff5fca2c044d535c2ea1a3f310df1e5bb06162e1f0b401b5c4af73fe6e2519ca2450d9d8c44cf268d + checksum: 0cd0d43e6e7dc7f9152fda8c8312b08321cda2f56ef53d6c22ebdd773abdc6f5d0a69008de90aa41908d00e2c1facb24715ff121274e689305c858355ff02c70 languageName: node linkType: hard @@ -3961,46 +3961,12 @@ __metadata: "@hyperlane-xyz/helloworld@1.5.0, @hyperlane-xyz/helloworld@workspace:typescript/helloworld": version: 0.0.0-use.local resolution: "@hyperlane-xyz/helloworld@workspace:typescript/helloworld" - dependencies: - "@hyperlane-xyz/sdk": 1.5.0 - "@nomiclabs/hardhat-ethers": ^2.2.1 - "@nomiclabs/hardhat-waffle": ^2.0.3 - "@openzeppelin/contracts-upgradeable": ^4.8.0 - "@trivago/prettier-plugin-sort-imports": ^3.2.0 - "@typechain/ethers-v5": 10.0.0 - "@typechain/hardhat": ^6.0.0 - "@types/mocha": ^9.1.0 - "@typescript-eslint/eslint-plugin": ^5.62.0 - "@typescript-eslint/parser": ^5.62.0 - chai: ^4.3.0 - eslint: ^8.16.0 - eslint-config-prettier: ^8.5.0 - ethereum-waffle: ^3.4.4 - ethers: ^5.7.2 - hardhat: ^2.16.1 - hardhat-gas-reporter: ^1.0.9 - prettier: ^2.4.1 - prettier-plugin-solidity: ^1.0.0-beta.5 - solhint: ^3.3.2 - solhint-plugin-prettier: ^0.0.5 - solidity-coverage: ^0.8.3 - ts-node: ^10.8.0 - typechain: 8.0.0 - typescript: ^5.1.6 - languageName: unknown - linkType: soft - -"@hyperlane-xyz/hyperlane-token@1.5.0, @hyperlane-xyz/hyperlane-token@workspace:typescript/token": - version: 0.0.0-use.local - resolution: "@hyperlane-xyz/hyperlane-token@workspace:typescript/token" dependencies: "@hyperlane-xyz/core": 1.5.0 "@hyperlane-xyz/sdk": 1.5.0 - "@hyperlane-xyz/utils": 1.5.0 "@nomiclabs/hardhat-ethers": ^2.2.1 "@nomiclabs/hardhat-waffle": ^2.0.3 "@openzeppelin/contracts-upgradeable": ^4.8.0 - "@solana/spl-token": ^0.3.8 "@trivago/prettier-plugin-sort-imports": ^3.2.0 "@typechain/ethers-v5": 10.0.0 "@typechain/hardhat": ^6.0.0 @@ -4038,7 +4004,6 @@ __metadata: "@ethersproject/hardware-wallets": ^5.7.0 "@ethersproject/providers": ^5.7.2 "@hyperlane-xyz/helloworld": 1.5.0 - "@hyperlane-xyz/hyperlane-token": 1.5.0 "@hyperlane-xyz/sdk": 1.5.0 "@hyperlane-xyz/utils": 1.5.0 "@nomiclabs/hardhat-ethers": ^2.2.1 @@ -4092,6 +4057,7 @@ __metadata: "@hyperlane-xyz/utils": 1.5.0 "@nomiclabs/hardhat-ethers": ^2.2.1 "@nomiclabs/hardhat-waffle": ^2.0.3 + "@solana/spl-token": ^0.3.8 "@solana/web3.js": ^1.78.0 "@types/coingecko-api": ^1.0.10 "@types/debug": ^4.1.7 @@ -4339,13 +4305,20 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.3.1, @noble/hashes@npm:^1.3.0, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:~1.3.0": +"@noble/hashes@npm:1.3.1, @noble/hashes@npm:^1.3.0, @noble/hashes@npm:~1.3.0": version: 1.3.1 resolution: "@noble/hashes@npm:1.3.1" checksum: 7fdefc0f7a0c1ec27acc6ff88841793e3f93ec4ce6b8a6a12bfc0dd70ae6b7c4c82fe305fdfeda1735d5ad4a9eebe761e6693b3d355689c559e91242f4bc95b1 languageName: node linkType: hard +"@noble/hashes@npm:^1.3.1": + version: 1.3.2 + resolution: "@noble/hashes@npm:1.3.2" + checksum: fe23536b436539d13f90e4b9be843cc63b1b17666a07634a2b1259dded6f490be3d050249e6af98076ea8f2ea0d56f578773c2197f2aa0eeaa5fba5bc18ba474 + languageName: node + linkType: hard + "@noble/secp256k1@npm:1.5.5, @noble/secp256k1@npm:~1.5.2": version: 1.5.5 resolution: "@noble/secp256k1@npm:1.5.5" @@ -5214,8 +5187,8 @@ __metadata: linkType: hard "@solana/web3.js@npm:^1.32.0": - version: 1.78.4 - resolution: "@solana/web3.js@npm:1.78.4" + version: 1.78.5 + resolution: "@solana/web3.js@npm:1.78.5" dependencies: "@babel/runtime": ^7.22.6 "@noble/curves": ^1.0.0 @@ -5232,7 +5205,7 @@ __metadata: node-fetch: ^2.6.12 rpc-websockets: ^7.5.1 superstruct: ^0.14.2 - checksum: e1c44c6cbec87cdfd4d6d23b4241b746e14ed3a9ca73d596693758d91ac825cecf579345da3b0b7bb5e54b6794791bc0eac02cadf11f1ec79e859b6536f26f11 + checksum: 66fe4ddcc073d0c539e23a2aae3ba23c081a11f5ebc8216dd18e0c6770f20e419c635a50529faa59baeec9722cd521a3502abc7cdf3b3d5f31b32066e0415c24 languageName: node linkType: hard @@ -14807,8 +14780,8 @@ __metadata: linkType: hard "node-fetch@npm:^2.6.12": - version: 2.6.13 - resolution: "node-fetch@npm:2.6.13" + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" dependencies: whatwg-url: ^5.0.0 peerDependencies: @@ -14816,7 +14789,7 @@ __metadata: peerDependenciesMeta: encoding: optional: true - checksum: 055845ae5b4796c78c7053564745345025cf959563b3568b43c385f67d311779e6b00e5fef6ed1b79f86ba4048e4b4b722e1aa948305521b9353eb7e788912c9 + checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 languageName: node linkType: hard