-
Notifications
You must be signed in to change notification settings - Fork 569
feat: Polygon ZKevm v2 hook and ism #4547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
61a1f84
ba05d39
628fc75
f73a953
0f8bc70
1b9ac7a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,110 @@ | ||||
| // SPDX-License-Identifier: MIT OR Apache-2.0 | ||||
| pragma solidity >=0.8.0; | ||||
|
|
||||
| /*@@@@@@@ @@@@@@@@@ | ||||
| @@@@@@@@@ @@@@@@@@@ | ||||
| @@@@@@@@@ @@@@@@@@@ | ||||
| @@@@@@@@@ @@@@@@@@@ | ||||
| @@@@@@@@@@@@@@@@@@@@@@@@@ | ||||
| @@@@@ HYPERLANE @@@@@@@ | ||||
| @@@@@@@@@@@@@@@@@@@@@@@@@ | ||||
| @@@@@@@@@ @@@@@@@@@ | ||||
| @@@@@@@@@ @@@@@@@@@ | ||||
| @@@@@@@@@ @@@@@@@@@ | ||||
| @@@@@@@@@ @@@@@@@@*/ | ||||
|
|
||||
| // ============ Internal Imports ============ | ||||
| import {StandardHookMetadata} from "./libs/StandardHookMetadata.sol"; | ||||
| import {TypeCasts} from "../libs/TypeCasts.sol"; | ||||
| import {Message} from "../libs/Message.sol"; | ||||
| import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; | ||||
|
|
||||
| // ============ External Imports ============ | ||||
| import {Address} from "@openzeppelin/contracts/utils/Address.sol"; | ||||
|
|
||||
| import {IPolygonZkEVMBridge} from "../interfaces/polygonZkevm/IPolygonZkEVMBridge.sol"; | ||||
| import {MailboxClient} from "../client/MailboxClient.sol"; | ||||
|
|
||||
| /** | ||||
| * @title PolygonZkevmHook | ||||
| * @notice Message hook to inform the {Polygon zkEVM chain Ism} of messages published through | ||||
| * the native Polygon zkEVM bridge bridge. | ||||
| */ | ||||
| contract PolygonZkevmHook is IPostDispatchHook, MailboxClient { | ||||
| using StandardHookMetadata for bytes; | ||||
| using Message for bytes; | ||||
| using TypeCasts for bytes32; | ||||
|
|
||||
| // ============ Immutable Variables ============ | ||||
| IPolygonZkEVMBridge public immutable zkEvmBridge; | ||||
|
|
||||
| // left-padded address for ISM to verify messages | ||||
| address public immutable ism; | ||||
| // Domain of chain on which the ISM is deployed | ||||
| uint32 public immutable destinationDomain; | ||||
| // Polygon ZkevmBridge uses networkId 0 for Mainnet and 1 for rollup | ||||
| uint32 public immutable zkEvmBridgeDestinationNetId; | ||||
|
|
||||
| constructor( | ||||
| address _mailbox, | ||||
| uint32 _destinationDomain, | ||||
| address _ism, | ||||
| address _zkEvmBridge, | ||||
| uint32 _zkEvmBridgeDestinationNetId | ||||
| ) MailboxClient(_mailbox) { | ||||
| require( | ||||
| Address.isContract(_zkEvmBridge), | ||||
| "PolygonzkEVMHook: invalid PolygonZkEVMBridge contract" | ||||
| ); | ||||
| require( | ||||
| _destinationDomain != 0, | ||||
| "PolygonzkEVMHook: invalid destination domain" | ||||
| ); | ||||
| require( | ||||
| _zkEvmBridgeDestinationNetId <= 1, | ||||
| "PolygonZkevmIsm: invalid ZkEVMBridge destination network id" | ||||
| ); | ||||
| ism = _ism; | ||||
| destinationDomain = _destinationDomain; | ||||
| zkEvmBridge = IPolygonZkEVMBridge(_zkEvmBridge); | ||||
| zkEvmBridgeDestinationNetId = uint8(_zkEvmBridgeDestinationNetId); | ||||
| } | ||||
|
|
||||
| /// @inheritdoc IPostDispatchHook | ||||
| function supportsMetadata( | ||||
| bytes calldata | ||||
| ) public pure virtual override returns (bool) { | ||||
| return true; | ||||
| } | ||||
|
|
||||
| /// @dev This value is hardcoded to 0 because the Polygon zkEVM bridge does not support fee quotes | ||||
| function quoteDispatch( | ||||
| bytes calldata, | ||||
| bytes calldata | ||||
| ) external pure override returns (uint256) { | ||||
| return 0; | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But I imagine there's still some additional overhead for the relayer to submit the tx on the destination chain. You can follow using a childHook which is effectively an IGP:
|
||||
| } | ||||
|
|
||||
| /// @inheritdoc IPostDispatchHook | ||||
| function postDispatch( | ||||
| bytes calldata metadata, | ||||
| bytes calldata message | ||||
| ) external payable override { | ||||
| require( | ||||
| metadata.msgValue(0) < 2 ** 255, | ||||
| "PolygonzkEVMHook: msgValue must be less than 2 ** 255" | ||||
| ); | ||||
| bytes32 messageId = message.id(); | ||||
|
|
||||
| zkEvmBridge.bridgeMessage{value: msg.value}( | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only send the metadata.msgValue(0) and refund the rest |
||||
| zkEvmBridgeDestinationNetId, | ||||
| address(ism), | ||||
| true, | ||||
| abi.encode(messageId) | ||||
| ); | ||||
| } | ||||
|
|
||||
| function hookType() external pure override returns (uint8) { | ||||
| return uint8(IPostDispatchHook.Types.POLYGON_ZKEVM); | ||||
| } | ||||
| } | ||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| // SPDX-License-Identifier: MIT OR Apache-2.0 | ||
| pragma solidity >=0.8.0; | ||
|
|
||
| /*@@@@@@@ @@@@@@@@@ | ||
| @@@@@@@@@ @@@@@@@@@ | ||
| @@@@@@@@@ @@@@@@@@@ | ||
| @@@@@@@@@ @@@@@@@@@ | ||
| @@@@@@@@@@@@@@@@@@@@@@@@@ | ||
| @@@@@ HYPERLANE @@@@@@@ | ||
| @@@@@@@@@@@@@@@@@@@@@@@@@ | ||
| @@@@@@@@@ @@@@@@@@@ | ||
| @@@@@@@@@ @@@@@@@@@ | ||
| @@@@@@@@@ @@@@@@@@@ | ||
| @@@@@@@@@ @@@@@@@@*/ | ||
|
|
||
| // ============ Internal Imports ============ | ||
| import {StandardHookMetadata} from "./libs/StandardHookMetadata.sol"; | ||
| import {TypeCasts} from "../libs/TypeCasts.sol"; | ||
| import {Message} from "../libs/Message.sol"; | ||
| import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; | ||
| import {IInterchainGasPaymaster} from "../interfaces/IInterchainGasPaymaster.sol"; | ||
|
|
||
| // ============ External Imports ============ | ||
| import {Address} from "@openzeppelin/contracts/utils/Address.sol"; | ||
|
|
||
| import {IPolygonZkEVMBridgeV2} from "../interfaces/polygonZkevm/IPolygonZkEVMBridgeV2.sol"; | ||
| import {MailboxClient} from "../client/MailboxClient.sol"; | ||
|
|
||
| /** | ||
| * @title PolygonzkEVMv2Hook | ||
| * @notice Message hook to inform the {Polygon zkEVM chain Ism} of messages published through | ||
| * the native Polygon zkEVM bridge bridge. | ||
| */ | ||
| contract PolygonZkevmV2Hook is IPostDispatchHook, MailboxClient { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inherit from AbstractMessageIdAuthHook here instead too |
||
| using StandardHookMetadata for bytes; | ||
| using Message for bytes; | ||
| using TypeCasts for bytes32; | ||
|
|
||
| uint256 private constant GAS_LIMIT = 150_000; | ||
| // ============ Immutable Variables ============ | ||
| IPolygonZkEVMBridgeV2 public immutable zkEvmBridge; | ||
| IInterchainGasPaymaster public immutable interchainGasPaymaster; | ||
| // address for ISM to verify messages | ||
| // left-padded address for ISM to verify messages | ||
| address public immutable ism; | ||
| // Domain of chain on which the ISM is deployed | ||
| uint32 public immutable destinationDomain; | ||
| // Polygon ZkevmBridge uses networkId 0 for Mainnet and 1 for rollup | ||
| uint32 public immutable zkEvmBridgeDestinationNetId; | ||
|
|
||
| error InvalidContract(string Contract); | ||
| error InvalidInput(string input); | ||
|
|
||
| constructor( | ||
| address _mailbox, | ||
| uint32 _destinationDomain, | ||
| address _ism, | ||
| address _zkEvmBridge, | ||
| uint32 _zkEvmBridgeDestinationNetId, | ||
| address _interchainGasPaymaster | ||
| ) MailboxClient(_mailbox) { | ||
| require( | ||
| Address.isContract(_zkEvmBridge), | ||
| "PolygonzkEVMv2Hook: invalid PolygonZkEVMBridge contract" | ||
| ); | ||
| require( | ||
| _destinationDomain != 0, | ||
| "PolygonzkEVMv2Hook: invalid destination domain" | ||
| ); | ||
| require( | ||
| _zkEvmBridgeDestinationNetId <= 1, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can only be 0 or 1 then? |
||
| "PolygonZkevmIsm: invalid ZkEVMBridge destination network id" | ||
| ); | ||
| require( | ||
| Address.isContract(_interchainGasPaymaster), | ||
| "PolygonzkEVMv2Hook: invalid Interchain Gas Paymaster contract" | ||
| ); | ||
| ism = _ism; | ||
| destinationDomain = _destinationDomain; | ||
| zkEvmBridge = IPolygonZkEVMBridgeV2(_zkEvmBridge); | ||
| zkEvmBridgeDestinationNetId = uint8(_zkEvmBridgeDestinationNetId); | ||
| interchainGasPaymaster = IInterchainGasPaymaster( | ||
| _interchainGasPaymaster | ||
| ); | ||
| } | ||
|
|
||
| /// @inheritdoc IPostDispatchHook | ||
| function supportsMetadata( | ||
| bytes calldata | ||
| ) public pure virtual override returns (bool) { | ||
| return true; | ||
| } | ||
|
|
||
| /// @dev This value is hardcoded to 0 because the Polygon zkEVM bridge does not support fee quotes | ||
| function quoteDispatch( | ||
| bytes calldata, | ||
| bytes calldata | ||
| ) external view override returns (uint256) { | ||
| return | ||
| interchainGasPaymaster.quoteGasPayment( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make this child hook |
||
| destinationDomain, | ||
| GAS_LIMIT | ||
| ); | ||
| } | ||
|
|
||
| /// @inheritdoc IPostDispatchHook | ||
| function postDispatch( | ||
| bytes calldata _metadata, | ||
| bytes calldata _message | ||
| ) external payable override { | ||
| bytes32 messageId = keccak256(_message); | ||
| uint256 gasPayment = interchainGasPaymaster.quoteGasPayment( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. childHook.quoteDispatch() |
||
| destinationDomain, | ||
| 150_000 | ||
| ); | ||
| require( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you don't need this require, igp will revert anyway |
||
| msg.value - _metadata.msgValue(0) >= gasPayment, | ||
| "PolygonzkEVMv2Hook: msgValue must be more than required gas" | ||
| ); | ||
|
|
||
| interchainGasPaymaster.payForGas{value: gasPayment}( | ||
| messageId, | ||
| _metadata.destination(), | ||
| 150_000, | ||
| msg.sender | ||
| ); | ||
|
|
||
| zkEvmBridge.bridgeMessage{value: msg.value - gasPayment}( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. metadata.msgValue(0) |
||
| zkEvmBridgeDestinationNetId, | ||
| address(ism), | ||
| true, | ||
| abi.encode(messageId) | ||
| ); | ||
| } | ||
|
|
||
| function hookType() external pure override returns (uint8) { | ||
| return uint8(IPostDispatchHook.Types.POLYGON_ZKEVM_V2); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // SPDX-License-Identifier: AGPL-3.0 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use forge submodules or npm for polygon dependencies, don't prefer to have dependencies vendored here |
||
|
|
||
| pragma solidity ^0.8.20; | ||
|
|
||
| interface IBasePolygonZkEVMGlobalExitRoot { | ||
| /** | ||
| * @dev Thrown when the caller is not the allowed contracts | ||
| */ | ||
| error OnlyAllowedContracts(); | ||
|
|
||
| function updateExitRoot(bytes32 newRollupExitRoot) external; | ||
|
|
||
| function globalExitRootMap( | ||
| bytes32 globalExitRootNum | ||
| ) external returns (uint256); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| // SPDX-License-Identifier: AGPL-3.0 | ||
|
|
||
| pragma solidity >=0.8.0; | ||
|
|
||
| /** | ||
| * @dev Define interface for PolygonZkEVM Bridge message receiver | ||
| */ | ||
| interface IBridgeMessageReceiver { | ||
| function onMessageReceived( | ||
| address originAddress, | ||
| uint32 originNetwork, | ||
| bytes memory data | ||
| ) external payable; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you inherit from AbstractMessageIdAuthHook here, it'll mean less code duplication?