commit
24ee39f8e3
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Add ether's error reasoning handling to SmartProvider to show clearer error messages |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Support proxiedFactories in HypERC20App and extend HypERC20Checker with ProxiedRouterChecker |
@ -1,8 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/helloworld': minor |
||||
'@hyperlane-xyz/widgets': minor |
||||
'@hyperlane-xyz/infra': minor |
||||
'@hyperlane-xyz/cli': minor |
||||
--- |
||||
|
||||
Update to registry v2.5.0 |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Deploy to arbitrumsepolia, basesepolia, ecotestnet, optimismsepolia, polygonamoy |
@ -1,7 +1,8 @@ |
||||
--- |
||||
'@hyperlane-xyz/infra': minor |
||||
'@hyperlane-xyz/cli': minor |
||||
'@hyperlane-xyz/sdk': minor |
||||
'@hyperlane-xyz/core': minor |
||||
--- |
||||
|
||||
Added SDK support for ArbL2ToL1Hook/ISM for selfrelay |
||||
Added sdk support for Stake weighted ISM |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/cli': patch |
||||
--- |
||||
|
||||
Require at least 1 chain selection in warp init |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Deploy to zircuit |
@ -1,6 +0,0 @@ |
||||
--- |
||||
"@hyperlane-xyz/cli": patch |
||||
"@hyperlane-xyz/sdk": patch |
||||
--- |
||||
|
||||
feat: Add long-running CLI relayer |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Update cosmos zod schema and enroll new validators for cheesechain, xlayer, zircuit, worldchain. |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': patch |
||||
--- |
||||
|
||||
Update ProxyAdminViolation interface to include proxyAdmin and proxy contract fields |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Adds CollateralFiat to token mapping which will output the correct standard to the warp deploy artifact. |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Deploy to solana + eclipse |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/cli': minor |
||||
--- |
||||
|
||||
Add output of hyperlane warp read to ./configs/warp-route-deployment.yaml |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/core': patch |
||||
--- |
||||
|
||||
fix: only evaluate dynamic revert reasons in reverting branch |
@ -1,6 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
'@hyperlane-xyz/core': minor |
||||
--- |
||||
|
||||
Added yield route with yield going to message recipient. |
@ -1,5 +0,0 @@ |
||||
--- |
||||
"@hyperlane-xyz/core": minor |
||||
--- |
||||
|
||||
feat: attributable fraud for signers |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/cli': minor |
||||
--- |
||||
|
||||
Remove registry.getUri() from core read logging to prevent registry error |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/cli': minor |
||||
--- |
||||
|
||||
Fixes the new chain message to display the correct command |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/core': minor |
||||
--- |
||||
|
||||
Implement checkpoint fraud proofs for use in slashing |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': minor |
||||
--- |
||||
|
||||
Supprt passing foreignDeployments to HypERC20App constructor |
@ -0,0 +1,5 @@ |
||||
--- |
||||
'@hyperlane-xyz/sdk': patch |
||||
--- |
||||
|
||||
Improved check for mailbox initialization |
@ -1,5 +0,0 @@ |
||||
--- |
||||
'@hyperlane-xyz/cli': minor |
||||
--- |
||||
|
||||
Add check & confirm for existing mailbox to core deploy to allow users to decide if they want to deploy a new mailbox |
@ -1 +1 @@ |
||||
a000b2a0e64b6cdd27b3edd98cbf2495f2725c64 |
||||
488c6eb828e46821e3858275c1e6f53bc5721db3 |
||||
|
@ -0,0 +1,77 @@ |
||||
use std::str::FromStr; |
||||
|
||||
use url::Url; |
||||
|
||||
use hyperlane_core::config::OperationBatchConfig; |
||||
use hyperlane_core::{ContractLocator, HyperlaneDomain, KnownHyperlaneDomain}; |
||||
|
||||
use crate::address::CosmosAddress; |
||||
use crate::grpc::{WasmGrpcProvider, WasmProvider}; |
||||
use crate::{ConnectionConf, CosmosAmount, RawCosmosAmount}; |
||||
|
||||
#[ignore] |
||||
#[tokio::test] |
||||
async fn test_wasm_contract_info_success() { |
||||
// given
|
||||
let provider = provider("neutron1sjzzd4gwkggy6hrrs8kxxatexzcuz3jecsxm3wqgregkulzj8r7qlnuef4"); |
||||
|
||||
// when
|
||||
let result = provider.wasm_contract_info().await; |
||||
|
||||
// then
|
||||
assert!(result.is_ok()); |
||||
|
||||
let contract_info = result.unwrap(); |
||||
|
||||
assert_eq!( |
||||
contract_info.creator, |
||||
"neutron1dwnrgwsf5c9vqjxsax04pdm0mx007yrre4yyvm", |
||||
); |
||||
assert_eq!( |
||||
contract_info.admin, |
||||
"neutron1fqf5mprg3f5hytvzp3t7spmsum6rjrw80mq8zgkc0h6rxga0dtzqws3uu7", |
||||
); |
||||
} |
||||
|
||||
#[ignore] |
||||
#[tokio::test] |
||||
async fn test_wasm_contract_info_no_contract() { |
||||
// given
|
||||
let provider = provider("neutron1dwnrgwsf5c9vqjxsax04pdm0mx007yrre4yyvm"); |
||||
|
||||
// when
|
||||
let result = provider.wasm_contract_info().await; |
||||
|
||||
// then
|
||||
assert!(result.is_err()); |
||||
} |
||||
|
||||
fn provider(address: &str) -> WasmGrpcProvider { |
||||
let domain = HyperlaneDomain::Known(KnownHyperlaneDomain::Neutron); |
||||
let address = CosmosAddress::from_str(address).unwrap(); |
||||
let locator = Some(ContractLocator::new(&domain, address.digest())); |
||||
|
||||
WasmGrpcProvider::new( |
||||
domain.clone(), |
||||
ConnectionConf::new( |
||||
vec![Url::parse("http://grpc-kralum.neutron-1.neutron.org:80").unwrap()], |
||||
"https://rpc-kralum.neutron-1.neutron.org".to_owned(), |
||||
"neutron-1".to_owned(), |
||||
"neutron".to_owned(), |
||||
"untrn".to_owned(), |
||||
RawCosmosAmount::new("untrn".to_owned(), "0".to_owned()), |
||||
32, |
||||
OperationBatchConfig { |
||||
batch_contract_address: None, |
||||
max_batch_size: 1, |
||||
}, |
||||
), |
||||
CosmosAmount { |
||||
denom: "untrn".to_owned(), |
||||
amount: Default::default(), |
||||
}, |
||||
locator, |
||||
None, |
||||
) |
||||
.unwrap() |
||||
} |
@ -0,0 +1,3 @@ |
||||
{ |
||||
"program_id": "HDXcKGggF4aLRE1Q6ApF2rLwriSQjpjrnE811cwH21mr" |
||||
} |
@ -1,7 +1,7 @@ |
||||
{ |
||||
"mailbox": "4rRZgaC1DaCqtWYLzg14ftuXKPuHe1nGEM6ZtNpim3Wz", |
||||
"validator_announce": "bn63TQYrzzK9H3XQwZ1gzGdNS91xkt5YaTinFPWyahR", |
||||
"multisig_ism_message_id": "2abS919HMBQ39GviSgjMQQf5L1G7cfdbAiNq61wQ8CvJ", |
||||
"multisig_ism_message_id": "HDXcKGggF4aLRE1Q6ApF2rLwriSQjpjrnE811cwH21mr", |
||||
"igp_program_id": "8cPZ6Lv49h1cYBb6q29E2pxn4xbWjJGxfarNE8LqP1Ks", |
||||
"overhead_igp_account": "5FG1TUuhXGKdMbbH8uHEnUghazD4aVfEPAgKLNGNx3SL", |
||||
"igp_account": "HkqbGqRX7Fi5pwqi8HkDaUhHK6mGWsy7Rt17fpgBrbP5" |
||||
|
@ -0,0 +1,10 @@ |
||||
{ |
||||
"eclipse": { |
||||
"hex": "0x6d8f3a8e68449b4c5fa5f09f9f9bf82607f6b2b1b6052260bf7c5c66aa5a5684", |
||||
"base58": "8Ng7TLE223sWcRjH7rEdUPoR3seaugqPw1djdQRRZ6Gj" |
||||
}, |
||||
"solana": { |
||||
"hex": "0x6903def7c07b2844eb549e7037651c07f508884e0c962345c8bb2b9834633e15", |
||||
"base58": "84wESfpyisKVYwkpaJpkHS6XxkLPC5bLZrTD1jQw1TrL" |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
{ |
||||
"solana": { |
||||
"type": "native", |
||||
"decimals": 9, |
||||
"interchainGasPaymaster": "HkqbGqRX7Fi5pwqi8HkDaUhHK6mGWsy7Rt17fpgBrbP5" |
||||
}, |
||||
"eclipse": { |
||||
"type": "synthetic", |
||||
"decimals": 9, |
||||
"name": "Solana", |
||||
"symbol": "SOL", |
||||
"uri": "https://github.com/hyperlane-xyz/hyperlane-registry/blob/b661127dd3dce5ea98b78ae0051fbd10c384b173/deployments/warp_routes/SOL/eclipse/metadata.json", |
||||
"interchainGasPaymaster": "AgjedtgQKTWGR77ULJ9j9AhLjNDk1D3BTtuxKmcZrJqE" |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
{ |
||||
"solana": { |
||||
"hex": "0xe9792265ec273ffc17731af890d3e9963e9d744e7b99f02491911ce1bb75b8cb", |
||||
"base58": "GiP8GwN1GsscVJvmKSD4muDEihRzZRa9mxnS1Toi64pa" |
||||
}, |
||||
"ethereum": { |
||||
"hex": "0x0000000000000000000000001d622da2ce4c4d9d4b0611718cb3bcdcad008dd4", |
||||
"base58": "111111111111Qk6NeeudaXPNPB2XfB1yQ9furMh" |
||||
} |
||||
} |
@ -0,0 +1,18 @@ |
||||
{ |
||||
"solana": { |
||||
"type": "synthetic", |
||||
"decimals": 9, |
||||
"name": "Renzo Restaked LST", |
||||
"symbol": "pzETH", |
||||
"uri": "https://raw.githubusercontent.com/hyperlane-xyz/hyperlane-registry/12660fd34d30e960a748d87408a8d88f634f7454/deployments/warp_routes/pzETH/ethereum-solana-metadata.json", |
||||
"interchainGasPaymaster": "5FG1TUuhXGKdMbbH8uHEnUghazD4aVfEPAgKLNGNx3SL", |
||||
"remoteDecimals": 18 |
||||
}, |
||||
"ethereum": { |
||||
"type": "collateral", |
||||
"decimals": 18, |
||||
"token": "0x8c9532a60e0e7c6bbd2b2c1303f63ace1c3e9811", |
||||
"foreignDeployment": "0x1D622da2ce4C4D9D4B0611718cb3BcDcAd008DD4", |
||||
"destinationGas": 200000 |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
//! Data structures for the protocol fee configuration.
|
||||
|
||||
use borsh::{BorshDeserialize, BorshSerialize}; |
||||
use solana_program::pubkey::Pubkey; |
||||
|
||||
/// The Protocol Fee configuration.
|
||||
#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone, Default)] |
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
||||
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] |
||||
pub struct ProtocolFee { |
||||
/// The current protocol fee, expressed in the lowest denomination.
|
||||
pub fee: u64, |
||||
/// The beneficiary of protocol fees.
|
||||
pub beneficiary: Pubkey, |
||||
} |
@ -0,0 +1,84 @@ |
||||
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||
pragma solidity >=0.8.0; |
||||
|
||||
/*@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@@@@@@@@@@@@@@@@@ |
||||
@@@@@ HYPERLANE @@@@@@@ |
||||
@@@@@@@@@@@@@@@@@@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@*/ |
||||
|
||||
// ============ Internal Imports ============ |
||||
import {AbstractPostDispatchHook, AbstractMessageIdAuthHook} from "./libs/AbstractMessageIdAuthHook.sol"; |
||||
import {StandardHookMetadata} from "./libs/StandardHookMetadata.sol"; |
||||
import {TypeCasts} from "../libs/TypeCasts.sol"; |
||||
import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol"; |
||||
|
||||
// ============ External Imports ============ |
||||
import {ICrossDomainMessenger} from "../interfaces/optimism/ICrossDomainMessenger.sol"; |
||||
|
||||
/** |
||||
* @title OPL2ToL1Hook |
||||
* @notice Message hook to inform the OPL2ToL1Ism of messages published through |
||||
* the native Optimism bridge. |
||||
* @notice This works only for L2 -> L1 messages and has the 7 day delay as specified by the OptimismPortal contract. |
||||
*/ |
||||
contract OPL2ToL1Hook is AbstractMessageIdAuthHook { |
||||
using StandardHookMetadata for bytes; |
||||
|
||||
// ============ Constants ============ |
||||
|
||||
// precompile contract on L2 for sending messages to L1 |
||||
ICrossDomainMessenger public immutable l2Messenger; |
||||
// Immutable quote amount |
||||
uint32 public immutable GAS_QUOTE; |
||||
|
||||
// ============ Constructor ============ |
||||
|
||||
constructor( |
||||
address _mailbox, |
||||
uint32 _destinationDomain, |
||||
bytes32 _ism, |
||||
address _l2Messenger, |
||||
uint32 _gasQuote |
||||
) AbstractMessageIdAuthHook(_mailbox, _destinationDomain, _ism) { |
||||
GAS_QUOTE = _gasQuote; |
||||
l2Messenger = ICrossDomainMessenger(_l2Messenger); |
||||
} |
||||
|
||||
/// @inheritdoc IPostDispatchHook |
||||
function hookType() external pure override returns (uint8) { |
||||
return uint8(IPostDispatchHook.Types.OP_L2_TO_L1); |
||||
} |
||||
|
||||
/// @inheritdoc AbstractPostDispatchHook |
||||
function _quoteDispatch( |
||||
bytes calldata, |
||||
bytes calldata |
||||
) internal view override returns (uint256) { |
||||
return GAS_QUOTE; |
||||
} |
||||
|
||||
// ============ Internal functions ============ |
||||
|
||||
/// @inheritdoc AbstractMessageIdAuthHook |
||||
function _sendMessageId( |
||||
bytes calldata metadata, |
||||
bytes memory payload |
||||
) internal override { |
||||
require( |
||||
msg.value >= metadata.msgValue(0) + GAS_QUOTE, |
||||
"OPL2ToL1Hook: insufficient msg.value" |
||||
); |
||||
l2Messenger.sendMessage{value: metadata.msgValue(0)}( |
||||
TypeCasts.bytes32ToAddress(ism), |
||||
payload, |
||||
GAS_QUOTE |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
// SPDX-License-Identifier: MIT |
||||
pragma solidity ^0.8.0; |
||||
|
||||
// author: OP Labs |
||||
// copied from https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-bedrock |
||||
interface IOptimismPortal { |
||||
/// @notice Struct representing a withdrawal transaction. |
||||
/// @custom:field nonce Nonce of the withdrawal transaction |
||||
/// @custom:field sender Address of the sender of the transaction. |
||||
/// @custom:field target Address of the recipient of the transaction. |
||||
/// @custom:field value Value to send to the recipient. |
||||
/// @custom:field gasLimit Gas limit of the transaction. |
||||
/// @custom:field data Data of the transaction. |
||||
struct WithdrawalTransaction { |
||||
uint256 nonce; |
||||
address sender; |
||||
address target; |
||||
uint256 value; |
||||
uint256 gasLimit; |
||||
bytes data; |
||||
} |
||||
|
||||
/// @notice Finalizes a withdrawal transaction. |
||||
/// @param _tx Withdrawal transaction to finalize. |
||||
function finalizeWithdrawalTransaction( |
||||
WithdrawalTransaction memory _tx |
||||
) external; |
||||
} |
@ -0,0 +1,109 @@ |
||||
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||
pragma solidity >=0.8.0; |
||||
|
||||
/*@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@@@@@@@@@@@@@@@@@ |
||||
@@@@@ HYPERLANE @@@@@@@ |
||||
@@@@@@@@@@@@@@@@@@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@@ |
||||
@@@@@@@@@ @@@@@@@@*/ |
||||
|
||||
// ============ Internal Imports ============ |
||||
|
||||
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol"; |
||||
import {TypeCasts} from "../../libs/TypeCasts.sol"; |
||||
import {Message} from "../../libs/Message.sol"; |
||||
import {OPL2ToL1Metadata} from "../../libs/OPL2ToL1Metadata.sol"; |
||||
import {AbstractMessageIdAuthorizedIsm} from "./AbstractMessageIdAuthorizedIsm.sol"; |
||||
|
||||
// ============ External Imports ============ |
||||
|
||||
import {ICrossDomainMessenger} from "../../interfaces/optimism/ICrossDomainMessenger.sol"; |
||||
import {IOptimismPortal} from "../../interfaces/optimism/IOptimismPortal.sol"; |
||||
import {CrossChainEnabledOptimism} from "@openzeppelin/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol"; |
||||
import {Address} from "@openzeppelin/contracts/utils/Address.sol"; |
||||
|
||||
/** |
||||
* @title OPL2ToL1Ism |
||||
* @notice Uses the native Optimism bridge to verify interchain messages from L2 to L1. |
||||
*/ |
||||
contract OPL2ToL1Ism is |
||||
CrossChainEnabledOptimism, |
||||
AbstractMessageIdAuthorizedIsm |
||||
{ |
||||
using TypeCasts for address; |
||||
using Message for bytes; |
||||
using OPL2ToL1Metadata for bytes; |
||||
|
||||
// ============ Constants ============ |
||||
|
||||
// module type for the ISM |
||||
uint8 public constant moduleType = |
||||
uint8(IInterchainSecurityModule.Types.OP_L2_TO_L1); |
||||
// OptimismPortal contract on L1 to finalize withdrawal from L1 |
||||
IOptimismPortal public immutable portal; |
||||
|
||||
// ============ Constructor ============ |
||||
|
||||
constructor(address _messenger) CrossChainEnabledOptimism(_messenger) { |
||||
address _portal = ICrossDomainMessenger(_messenger).PORTAL(); |
||||
require( |
||||
Address.isContract(_portal), |
||||
"OPL2ToL1Ism: invalid OptimismPortal contract" |
||||
); |
||||
portal = IOptimismPortal(_portal); |
||||
} |
||||
|
||||
// ============ External Functions ============ |
||||
|
||||
/// @inheritdoc IInterchainSecurityModule |
||||
function verify( |
||||
bytes calldata metadata, |
||||
bytes calldata message |
||||
) external override returns (bool) { |
||||
bool verified = isVerified(message); |
||||
if (!verified) { |
||||
_verifyWithPortalCall(metadata, message); |
||||
} |
||||
releaseValueToRecipient(message); |
||||
return true; |
||||
} |
||||
|
||||
// ============ Internal function ============ |
||||
|
||||
/** |
||||
* @notice Verify message directly using the portal.finalizeWithdrawal function. |
||||
* @dev This is a fallback in case the message is not verified by the stateful verify function first. |
||||
*/ |
||||
function _verifyWithPortalCall( |
||||
bytes calldata metadata, |
||||
bytes calldata message |
||||
) internal { |
||||
require( |
||||
metadata.checkCalldataLength(), |
||||
"OPL2ToL1Ism: invalid data length" |
||||
); |
||||
require( |
||||
metadata.messageId() == message.id(), |
||||
"OPL2ToL1Ism: invalid message id" |
||||
); |
||||
|
||||
IOptimismPortal.WithdrawalTransaction memory withdrawal = abi.decode( |
||||
metadata, |
||||
(IOptimismPortal.WithdrawalTransaction) |
||||
); |
||||
// if the finalizeWithdrawalTransaction call is successful, the message is verified |
||||
portal.finalizeWithdrawalTransaction(withdrawal); |
||||
} |
||||
|
||||
/// @inheritdoc AbstractMessageIdAuthorizedIsm |
||||
function _isAuthorized() internal view override returns (bool) { |
||||
return |
||||
_crossChainSender() == TypeCasts.bytes32ToAddress(authorizedHook); |
||||
} |
||||
} |
@ -0,0 +1,62 @@ |
||||
// SPDX-License-Identifier: MIT OR Apache-2.0 |
||||
pragma solidity >=0.8.0; |
||||
|
||||
/** |
||||
* @title Hyperlane OPL2ToL1Metadata Library |
||||
* @notice Library for formatted metadata used by OPL2ToL1Ism |
||||
*/ |
||||
library OPL2ToL1Metadata { |
||||
// bottom offset to the start of message id in the metadata |
||||
uint256 private constant MESSAGE_ID_OFFSET = 88; |
||||
// from IOptimismPortal.WithdrawalTransaction |
||||
// Σ { |
||||
// nonce = 32 bytes |
||||
// PADDING + sender = 32 bytes |
||||
// PADDING + target = 32 bytes |
||||
// value = 32 bytes |
||||
// gasLimit = 32 bytes |
||||
// _data |
||||
// OFFSET = 32 bytes |
||||
// LENGTH = 32 bytes |
||||
// } = 252 bytes |
||||
uint256 private constant FIXED_METADATA_LENGTH = 252; |
||||
// metadata here is double encoded call relayMessage(..., verifyMessageId) |
||||
// Σ { |
||||
// _selector = 4 bytes |
||||
// _nonce = 32 bytes |
||||
// PADDING + _sender = 32 bytes |
||||
// PADDING + _target = 32 bytes |
||||
// _value = 32 bytes |
||||
// _minGasLimit = 32 bytes |
||||
// _data |
||||
// OFFSET = 32 bytes |
||||
// LENGTH = 32 bytes |
||||
// PADDING + verifyMessageId = 64 bytes |
||||
// } = 292 bytes |
||||
uint256 private constant MESSENGER_CALLDATA_LENGTH = 292; |
||||
|
||||
/** |
||||
* @notice Returns the message ID. |
||||
* @param _metadata OptimismPortal.WithdrawalTransaction encoded calldata |
||||
* @return ID of `_metadata` |
||||
*/ |
||||
function messageId( |
||||
bytes calldata _metadata |
||||
) internal pure returns (bytes32) { |
||||
uint256 metadataLength = _metadata.length; |
||||
return |
||||
bytes32( |
||||
_metadata[metadataLength - MESSAGE_ID_OFFSET:metadataLength - |
||||
MESSAGE_ID_OFFSET + |
||||
32] |
||||
); |
||||
} |
||||
|
||||
function checkCalldataLength( |
||||
bytes calldata _metadata |
||||
) internal pure returns (bool) { |
||||
return |
||||
_metadata.length == |
||||
MESSENGER_CALLDATA_LENGTH + FIXED_METADATA_LENGTH; |
||||
} |
||||
} |
@ -0,0 +1,61 @@ |
||||
// SPDX-License-Identifier: MIT |
||||
pragma solidity ^0.8.0; |
||||
|
||||
import {CallLib} from "../middleware/libs/Call.sol"; |
||||
import {TypeCasts} from "../libs/TypeCasts.sol"; |
||||
import {ICrossDomainMessenger} from "../interfaces/optimism/ICrossDomainMessenger.sol"; |
||||
import {IOptimismPortal} from "../interfaces/optimism/IOptimismPortal.sol"; |
||||
|
||||
// for both L1 and L2 |
||||
contract MockOptimismMessenger is ICrossDomainMessenger { |
||||
address public xDomainMessageSender; |
||||
address public PORTAL; |
||||
|
||||
function sendMessage( |
||||
address _target, |
||||
bytes calldata _message, |
||||
uint32 _gasLimit |
||||
) external payable {} |
||||
|
||||
function relayMessage( |
||||
uint256 /*_nonce*/, |
||||
address /*_sender*/, |
||||
address _target, |
||||
uint256 _value, |
||||
uint256 /*_minGasLimit*/, |
||||
bytes calldata _message |
||||
) external payable { |
||||
CallLib.Call memory call = CallLib.Call( |
||||
TypeCasts.addressToBytes32(_target), |
||||
_value, |
||||
_message |
||||
); |
||||
CallLib.call(call); |
||||
} |
||||
|
||||
function OTHER_MESSENGER() external view returns (address) {} |
||||
|
||||
function setXDomainMessageSender(address _sender) external { |
||||
xDomainMessageSender = _sender; |
||||
} |
||||
|
||||
function setPORTAL(address _portal) external { |
||||
PORTAL = _portal; |
||||
} |
||||
} |
||||
|
||||
// mock deployment on L1 |
||||
contract MockOptimismPortal is IOptimismPortal { |
||||
error WithdrawalTransactionFailed(); |
||||
|
||||
function finalizeWithdrawalTransaction( |
||||
WithdrawalTransaction memory _tx |
||||
) external { |
||||
CallLib.Call memory call = CallLib.Call( |
||||
TypeCasts.addressToBytes32(_tx.target), |
||||
_tx.value, |
||||
_tx.data |
||||
); |
||||
CallLib.call(call); |
||||
} |
||||
} |
@ -0,0 +1,320 @@ |
||||
// SPDX-License-Identifier: MIT or Apache-2.0 |
||||
pragma solidity ^0.8.13; |
||||
|
||||
import {Test} from "forge-std/Test.sol"; |
||||
|
||||
import {TypeCasts} from "../../contracts/libs/TypeCasts.sol"; |
||||
import {Message} from "../../contracts/libs/Message.sol"; |
||||
import {MessageUtils} from "./IsmTestUtils.sol"; |
||||
import {StandardHookMetadata} from "../../contracts/hooks/libs/StandardHookMetadata.sol"; |
||||
import {IOptimismPortal} from "../../contracts/interfaces/optimism/IOptimismPortal.sol"; |
||||
import {ICrossDomainMessenger} from "../../contracts/interfaces/optimism/ICrossDomainMessenger.sol"; |
||||
import {AbstractMessageIdAuthorizedIsm} from "../../contracts/isms/hook/AbstractMessageIdAuthorizedIsm.sol"; |
||||
import {TestMailbox} from "../../contracts/test/TestMailbox.sol"; |
||||
import {TestRecipient} from "../../contracts/test/TestRecipient.sol"; |
||||
import {MockOptimismMessenger, MockOptimismPortal} from "../../contracts/mock/MockOptimism.sol"; |
||||
import {OPL2ToL1Hook} from "../../contracts/hooks/OPL2ToL1Hook.sol"; |
||||
import {OPL2ToL1Ism} from "../../contracts/isms/hook/OPL2ToL1Ism.sol"; |
||||
|
||||
contract OPL2ToL1IsmTest is Test { |
||||
uint8 internal constant HYPERLANE_VERSION = 1; |
||||
uint32 internal constant MAINNET_DOMAIN = 1; |
||||
uint32 internal constant OPTIMISM_DOMAIN = 10; |
||||
uint32 internal constant GAS_QUOTE = 120_000; |
||||
|
||||
address internal constant L2_MESSENGER_ADDRESS = |
||||
0x4200000000000000000000000000000000000007; |
||||
|
||||
uint256 internal constant MOCK_NONCE = 0; |
||||
|
||||
TestMailbox public l2Mailbox; |
||||
TestRecipient internal testRecipient; |
||||
bytes internal testMessage = |
||||
abi.encodePacked("Hello from the other chain!"); |
||||
bytes internal encodedMessage; |
||||
bytes internal testMetadata = |
||||
StandardHookMetadata.overrideRefundAddress(address(this)); |
||||
bytes32 internal messageId; |
||||
|
||||
MockOptimismPortal internal portal; |
||||
MockOptimismMessenger internal l1Messenger; |
||||
OPL2ToL1Hook public hook; |
||||
OPL2ToL1Ism public ism; |
||||
|
||||
/////////////////////////////////////////////////////////////////// |
||||
/// SETUP /// |
||||
/////////////////////////////////////////////////////////////////// |
||||
|
||||
function setUp() public { |
||||
// Optimism messenger mock setup |
||||
vm.etch( |
||||
L2_MESSENGER_ADDRESS, |
||||
address(new MockOptimismMessenger()).code |
||||
); |
||||
|
||||
testRecipient = new TestRecipient(); |
||||
|
||||
encodedMessage = _encodeTestMessage(); |
||||
messageId = Message.id(encodedMessage); |
||||
} |
||||
|
||||
function deployHook() public { |
||||
l2Mailbox = new TestMailbox(OPTIMISM_DOMAIN); |
||||
hook = new OPL2ToL1Hook( |
||||
address(l2Mailbox), |
||||
MAINNET_DOMAIN, |
||||
TypeCasts.addressToBytes32(address(ism)), |
||||
L2_MESSENGER_ADDRESS, |
||||
GAS_QUOTE |
||||
); |
||||
} |
||||
|
||||
function deployIsm() public { |
||||
l1Messenger = new MockOptimismMessenger(); |
||||
portal = new MockOptimismPortal(); |
||||
l1Messenger.setPORTAL(address(portal)); |
||||
|
||||
ism = new OPL2ToL1Ism(address(l1Messenger)); |
||||
} |
||||
|
||||
function deployAll() public { |
||||
deployIsm(); |
||||
deployHook(); |
||||
|
||||
l1Messenger.setXDomainMessageSender(address(hook)); |
||||
ism.setAuthorizedHook(TypeCasts.addressToBytes32(address(hook))); |
||||
} |
||||
|
||||
function test_postDispatch() public { |
||||
deployAll(); |
||||
|
||||
bytes memory encodedHookData = abi.encodeCall( |
||||
AbstractMessageIdAuthorizedIsm.verifyMessageId, |
||||
(messageId) |
||||
); |
||||
|
||||
l2Mailbox.updateLatestDispatchedId(messageId); |
||||
|
||||
vm.expectCall( |
||||
L2_MESSENGER_ADDRESS, |
||||
abi.encodeCall( |
||||
ICrossDomainMessenger.sendMessage, |
||||
(address(ism), encodedHookData, GAS_QUOTE) |
||||
) |
||||
); |
||||
|
||||
hook.postDispatch{value: GAS_QUOTE}(testMetadata, encodedMessage); |
||||
} |
||||
|
||||
function testFork_postDispatch_revertWhen_chainIDNotSupported() public { |
||||
deployAll(); |
||||
|
||||
bytes memory message = MessageUtils.formatMessage( |
||||
0, |
||||
uint32(0), |
||||
OPTIMISM_DOMAIN, |
||||
TypeCasts.addressToBytes32(address(this)), |
||||
2, // wrong domain |
||||
TypeCasts.addressToBytes32(address(testRecipient)), |
||||
testMessage |
||||
); |
||||
|
||||
l2Mailbox.updateLatestDispatchedId(Message.id(message)); |
||||
vm.expectRevert( |
||||
"AbstractMessageIdAuthHook: invalid destination domain" |
||||
); |
||||
hook.postDispatch(testMetadata, message); |
||||
} |
||||
|
||||
function test_postDispatch_revertWhen_notLastDispatchedMessage() public { |
||||
deployAll(); |
||||
|
||||
vm.expectRevert( |
||||
"AbstractMessageIdAuthHook: message not latest dispatched" |
||||
); |
||||
hook.postDispatch(testMetadata, encodedMessage); |
||||
} |
||||
|
||||
function test_verify_directWithdrawalCall() public { |
||||
deployAll(); |
||||
|
||||
bytes memory encodedWithdrawalTx = _encodeFinalizeWithdrawalTx( |
||||
address(ism), |
||||
0, |
||||
messageId |
||||
); |
||||
|
||||
assertTrue(ism.verify(encodedWithdrawalTx, encodedMessage)); |
||||
} |
||||
|
||||
function test_verify_directWithdrawalCall_revertsWhen_invalidSender() |
||||
public |
||||
{ |
||||
deployAll(); |
||||
l1Messenger.setXDomainMessageSender(address(this)); |
||||
|
||||
bytes memory encodedWithdrawalTx = _encodeFinalizeWithdrawalTx( |
||||
address(ism), |
||||
0, |
||||
messageId |
||||
); |
||||
|
||||
vm.expectRevert(); // evmRevert in MockOptimismPortal |
||||
ism.verify(encodedWithdrawalTx, encodedMessage); |
||||
} |
||||
|
||||
function test_verify_statefulVerify() public { |
||||
deployAll(); |
||||
|
||||
vm.deal(address(portal), 1 ether); |
||||
IOptimismPortal.WithdrawalTransaction |
||||
memory withdrawal = IOptimismPortal.WithdrawalTransaction({ |
||||
nonce: MOCK_NONCE, |
||||
sender: L2_MESSENGER_ADDRESS, |
||||
target: address(l1Messenger), |
||||
value: 1 ether, |
||||
gasLimit: uint256(GAS_QUOTE), |
||||
data: _encodeMessengerCalldata(address(ism), 1 ether, messageId) |
||||
}); |
||||
portal.finalizeWithdrawalTransaction(withdrawal); |
||||
|
||||
vm.etch(address(portal), new bytes(0)); // this is a way to test that the portal isn't called again |
||||
assertTrue(ism.verify(new bytes(0), encodedMessage)); |
||||
assertEq(address(testRecipient).balance, 1 ether); // testing msg.value |
||||
} |
||||
|
||||
function test_verify_statefulAndDirectWithdrawal() public { |
||||
deployAll(); |
||||
|
||||
IOptimismPortal.WithdrawalTransaction |
||||
memory withdrawal = IOptimismPortal.WithdrawalTransaction({ |
||||
nonce: MOCK_NONCE, |
||||
sender: L2_MESSENGER_ADDRESS, |
||||
target: address(l1Messenger), |
||||
value: 0, |
||||
gasLimit: uint256(GAS_QUOTE), |
||||
data: _encodeMessengerCalldata(address(ism), 0, messageId) |
||||
}); |
||||
portal.finalizeWithdrawalTransaction(withdrawal); |
||||
|
||||
bytes memory encodedWithdrawalTx = _encodeFinalizeWithdrawalTx( |
||||
address(ism), |
||||
0, |
||||
messageId |
||||
); |
||||
|
||||
vm.etch(address(portal), new bytes(0)); // this is a way to test that the portal isn't called again |
||||
assertTrue(ism.verify(encodedWithdrawalTx, encodedMessage)); |
||||
} |
||||
|
||||
function test_verify_revertsWhen_noStatefulAndDirectWithdrawal() public { |
||||
deployAll(); |
||||
|
||||
vm.expectRevert(); |
||||
ism.verify(new bytes(0), encodedMessage); |
||||
} |
||||
|
||||
function test_verify_revertsWhen_invalidIsm() public { |
||||
deployAll(); |
||||
|
||||
bytes memory encodedWithdrawalTx = _encodeFinalizeWithdrawalTx( |
||||
address(this), |
||||
0, |
||||
messageId |
||||
); |
||||
|
||||
vm.expectRevert(); // evmRevert in MockOptimismPortal |
||||
ism.verify(encodedWithdrawalTx, encodedMessage); |
||||
} |
||||
|
||||
function test_verify_revertsWhen_incorrectMessageId() public { |
||||
deployAll(); |
||||
|
||||
bytes32 incorrectMessageId = keccak256("incorrect message id"); |
||||
|
||||
bytes memory encodedWithdrawalTx = _encodeFinalizeWithdrawalTx( |
||||
address(this), |
||||
0, |
||||
incorrectMessageId |
||||
); |
||||
|
||||
// through portal call |
||||
vm.expectRevert("OPL2ToL1Ism: invalid message id"); |
||||
ism.verify(encodedWithdrawalTx, encodedMessage); |
||||
|
||||
// through statefulVerify |
||||
IOptimismPortal.WithdrawalTransaction |
||||
memory withdrawal = IOptimismPortal.WithdrawalTransaction({ |
||||
nonce: MOCK_NONCE, |
||||
sender: L2_MESSENGER_ADDRESS, |
||||
target: address(l1Messenger), |
||||
value: 0, |
||||
gasLimit: uint256(GAS_QUOTE), |
||||
data: _encodeMessengerCalldata( |
||||
address(ism), |
||||
0, |
||||
incorrectMessageId |
||||
) |
||||
}); |
||||
portal.finalizeWithdrawalTransaction(withdrawal); |
||||
|
||||
vm.etch(address(portal), new bytes(0)); // to stop the portal route |
||||
vm.expectRevert(); // evmRevert() |
||||
assertFalse(ism.verify(new bytes(0), encodedMessage)); |
||||
} |
||||
|
||||
/* ============ helper functions ============ */ |
||||
|
||||
function _encodeTestMessage() internal view returns (bytes memory) { |
||||
return |
||||
MessageUtils.formatMessage( |
||||
HYPERLANE_VERSION, |
||||
uint32(0), |
||||
OPTIMISM_DOMAIN, |
||||
TypeCasts.addressToBytes32(address(this)), |
||||
MAINNET_DOMAIN, |
||||
TypeCasts.addressToBytes32(address(testRecipient)), |
||||
testMessage |
||||
); |
||||
} |
||||
|
||||
function _encodeMessengerCalldata( |
||||
address _ism, |
||||
uint256 _value, |
||||
bytes32 _messageId |
||||
) internal view returns (bytes memory) { |
||||
bytes memory encodedHookData = abi.encodeCall( |
||||
AbstractMessageIdAuthorizedIsm.verifyMessageId, |
||||
(_messageId) |
||||
); |
||||
|
||||
return |
||||
abi.encodeCall( |
||||
ICrossDomainMessenger.relayMessage, |
||||
( |
||||
MOCK_NONCE, |
||||
address(hook), |
||||
_ism, |
||||
_value, |
||||
uint256(GAS_QUOTE), |
||||
encodedHookData |
||||
) |
||||
); |
||||
} |
||||
|
||||
function _encodeFinalizeWithdrawalTx( |
||||
address _ism, |
||||
uint256 _value, |
||||
bytes32 _messageId |
||||
) internal view returns (bytes memory) { |
||||
return |
||||
abi.encode( |
||||
MOCK_NONCE, |
||||
L2_MESSENGER_ADDRESS, |
||||
l1Messenger, |
||||
_value, |
||||
uint256(GAS_QUOTE), |
||||
_encodeMessengerCalldata(_ism, _value, _messageId) |
||||
); |
||||
} |
||||
} |
@ -1 +1 @@ |
||||
export const VERSION = '5.0.0'; |
||||
export const VERSION = '5.1.0'; |
||||
|
@ -1,11 +1,8 @@ |
||||
{ |
||||
"ancient8": { |
||||
"HypERC20": "0x97423A68BAe94b5De52d767a17aBCc54c157c0E5", |
||||
"synthetic": "0x97423A68BAe94b5De52d767a17aBCc54c157c0E5" |
||||
}, |
||||
"ethereum": { |
||||
"HypERC20Collateral": "0x8b4192B9Ad1fCa440A5808641261e5289e6de95D", |
||||
"collateral": "0x8b4192B9Ad1fCa440A5808641261e5289e6de95D", |
||||
"proxyAdmin": "0x7d0c8b23c5b35091972023ccc689cfedcd881c7d" |
||||
"HypERC20Collateral": "0x1D622da2ce4C4D9D4B0611718cb3BcDcAd008DD4", |
||||
"collateral": "0x1D622da2ce4C4D9D4B0611718cb3BcDcAd008DD4", |
||||
"proxyAdmin": "0xe41a3270875f28A03312877cD95A01e9a53664b1", |
||||
"timelockController": "0x0000000000000000000000000000000000000000" |
||||
} |
||||
} |
||||
|
@ -0,0 +1,34 @@ |
||||
import { ethers } from 'ethers'; |
||||
|
||||
import { |
||||
ChainMap, |
||||
RouterConfig, |
||||
TokenRouterConfig, |
||||
TokenType, |
||||
} from '@hyperlane-xyz/sdk'; |
||||
|
||||
import { DEPLOYER } from '../../owners.js'; |
||||
|
||||
export const getEthereumSolanaPzETHWarpConfig = async ( |
||||
routerConfig: ChainMap<RouterConfig>, |
||||
): Promise<ChainMap<TokenRouterConfig>> => { |
||||
// @ts-ignore - foreignDeployment configs don't conform to the TokenRouterConfig
|
||||
const solana: TokenRouterConfig = { |
||||
type: TokenType.synthetic, |
||||
foreignDeployment: 'GiP8GwN1GsscVJvmKSD4muDEihRzZRa9mxnS1Toi64pa', |
||||
gas: 300_000, |
||||
}; |
||||
|
||||
const ethereum: TokenRouterConfig = { |
||||
...routerConfig.ethereum, |
||||
type: TokenType.collateral, |
||||
interchainSecurityModule: ethers.constants.AddressZero, |
||||
token: '0x8c9532a60e0e7c6bbd2b2c1303f63ace1c3e9811', |
||||
owner: DEPLOYER, |
||||
}; |
||||
|
||||
return { |
||||
solana, |
||||
ethereum, |
||||
}; |
||||
}; |
@ -0,0 +1,190 @@ |
||||
import { |
||||
ChainMap, |
||||
IsmType, |
||||
RouterConfig, |
||||
TokenRouterConfig, |
||||
TokenType, |
||||
buildAggregationIsmConfigs, |
||||
} from '@hyperlane-xyz/sdk'; |
||||
import { symmetricDifference } from '@hyperlane-xyz/utils'; |
||||
|
||||
import { getRegistry } from '../../chains.js'; |
||||
|
||||
const lockbox = '0xC8140dA31E6bCa19b287cC35531c2212763C2059'; |
||||
const xERC20 = '0x2416092f143378750bb29b79eD961ab195CcEea5'; |
||||
const lockboxChain = 'ethereum'; |
||||
// over the default 100k to account for xerc20 gas + ISM overhead over the default ISM https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/49f41d9759fd515bfd89e6e22e799c41b27b4119/typescript/sdk/src/router/GasRouterDeployer.ts#L14
|
||||
const warpRouteOverheadGas = 200_000; |
||||
|
||||
const chainsToDeploy = [ |
||||
'arbitrum', |
||||
'optimism', |
||||
'base', |
||||
'blast', |
||||
'bsc', |
||||
'mode', |
||||
'linea', |
||||
'ethereum', |
||||
'fraxtal', |
||||
'zircuit', |
||||
]; |
||||
|
||||
const ezEthValidators = { |
||||
arbitrum: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x9bccfad3bd12ef0ee8ae839dd9ed7835bccadc9d', // Everclear
|
||||
'0xc27032c6bbd48c20005f552af3aaa0dbf14260f3', // Renzo
|
||||
], |
||||
}, |
||||
optimism: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x6f4cb8e96db5d44422a4495faa73fffb9d30e9e2', // Everclear
|
||||
'0xe2593d205f5e7f74a50fa900824501084e092ebd', // Renzo
|
||||
], |
||||
}, |
||||
base: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x25ba4ee5268cbfb8d69bac531aa10368778702bd', // Renzo
|
||||
'0x9ec803b503e9c7d2611e231521ef3fde73f7a21c', // Everclear
|
||||
], |
||||
}, |
||||
blast: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x1652d8ba766821cf01aeea34306dfc1cab964a32', // Everclear
|
||||
'0x54bb0036f777202371429e062fe6aee0d59442f9', // Renzo
|
||||
], |
||||
}, |
||||
bsc: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x3156db97a3b3e2dcc3d69fddfd3e12dc7c937b6d', // Renzo
|
||||
'0x9a0326c43e4713ae2477f09e0f28ffedc24d8266', // Everclear
|
||||
], |
||||
}, |
||||
mode: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x456fbbe05484fc9f2f38ea09648424f54d6872be', // Everclear
|
||||
'0x7e29608c6e5792bbf9128599ca309be0728af7b4', // Renzo
|
||||
], |
||||
}, |
||||
linea: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x06a5a2a429560034d38bf62ca6d470942535947e', // Everclear
|
||||
'0xcb3e44edd2229860bdbaa58ba2c3817d111bee9a', // Renzo
|
||||
], |
||||
}, |
||||
ethereum: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x1fd889337f60986aa57166bc5ac121efd13e4fdd', // Everclear
|
||||
'0xc7f7b94a6baf2fffa54dfe1dde6e5fcbb749e04f', // Renzo
|
||||
], |
||||
}, |
||||
fraxtal: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x25b3a88f7cfd3c9f7d7e32b295673a16a6ddbd91', // luganodes
|
||||
'0xe986f457965227a05dcf984c8d0c29e01253c44d', // Renzo
|
||||
], |
||||
}, |
||||
zircuit: { |
||||
threshold: 1, |
||||
validators: [ |
||||
'0x1da9176c2ce5cc7115340496fa7d1800a98911ce', // Renzo
|
||||
'0x7ac6584c068eb2a72d4db82a7b7cd5ab34044061', // luganodes
|
||||
], |
||||
}, |
||||
}; |
||||
|
||||
const ezEthSafes: Record<string, string> = { |
||||
arbitrum: '0x0e60fd361fF5b90088e1782e6b21A7D177d462C5', |
||||
optimism: '0x8410927C286A38883BC23721e640F31D3E3E79F8', |
||||
base: '0x8410927C286A38883BC23721e640F31D3E3E79F8', |
||||
blast: '0xda7dBF0DB81882372B598a715F86eD5254A01b0a', |
||||
bsc: '0x0e60fd361fF5b90088e1782e6b21A7D177d462C5', |
||||
mode: '0x7791eeA3484Ba4E5860B7a2293840767619c2B58', |
||||
linea: '0xb7092685571B49786F1248c6205B5ac3A691c65E', |
||||
ethereum: '0xD1e6626310fD54Eceb5b9a51dA2eC329D6D4B68A', |
||||
fraxtal: '0x8410927C286A38883BC23721e640F31D3E3E79F8', |
||||
zircuit: '0x8410927C286A38883BC23721e640F31D3E3E79F8', |
||||
}; |
||||
|
||||
export const getRenzoEZETHWarpConfig = async (): Promise< |
||||
ChainMap<TokenRouterConfig> |
||||
> => { |
||||
const registry = await getRegistry(); |
||||
|
||||
const validatorDiff = symmetricDifference( |
||||
new Set(chainsToDeploy), |
||||
new Set(Object.keys(ezEthValidators)), |
||||
); |
||||
const safeDiff = symmetricDifference( |
||||
new Set(chainsToDeploy), |
||||
new Set(Object.keys(ezEthSafes)), |
||||
); |
||||
if (validatorDiff.size > 0) { |
||||
throw new Error( |
||||
`chainsToDeploy !== validatorConfig, diff is ${Array.from( |
||||
validatorDiff, |
||||
).join(', ')}`,
|
||||
); |
||||
} |
||||
if (safeDiff.size > 0) { |
||||
throw new Error( |
||||
`chainsToDeploy !== safeDiff, diff is ${Array.from(safeDiff).join(', ')}`, |
||||
); |
||||
} |
||||
|
||||
const tokenConfig = Object.fromEntries<TokenRouterConfig>( |
||||
await Promise.all( |
||||
chainsToDeploy.map( |
||||
async (chain): Promise<[string, TokenRouterConfig]> => { |
||||
const ret: [string, TokenRouterConfig] = [ |
||||
chain, |
||||
{ |
||||
isNft: false, |
||||
type: |
||||
chain === lockboxChain |
||||
? TokenType.XERC20Lockbox |
||||
: TokenType.XERC20, |
||||
token: chain === lockboxChain ? lockbox : xERC20, |
||||
owner: ezEthSafes[chain], |
||||
gas: warpRouteOverheadGas, |
||||
mailbox: (await registry.getChainAddresses(chain))!.mailbox, |
||||
interchainSecurityModule: { |
||||
type: IsmType.AGGREGATION, |
||||
threshold: 2, |
||||
modules: [ |
||||
{ |
||||
type: IsmType.ROUTING, |
||||
owner: ezEthSafes[chain], |
||||
domains: buildAggregationIsmConfigs( |
||||
chain, |
||||
chainsToDeploy, |
||||
ezEthValidators, |
||||
), |
||||
}, |
||||
{ |
||||
type: IsmType.FALLBACK_ROUTING, |
||||
domains: {}, |
||||
owner: ezEthSafes[chain], |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
]; |
||||
|
||||
return ret; |
||||
}, |
||||
), |
||||
), |
||||
); |
||||
|
||||
return tokenConfig; |
||||
}; |
@ -0,0 +1,32 @@ |
||||
{ |
||||
"arbitrum": { |
||||
"xERC20": "0xB26bBfC6d1F469C821Ea25099017862e7368F4E8" |
||||
}, |
||||
"optimism": { |
||||
"xERC20": "0xacEB607CdF59EB8022Cc0699eEF3eCF246d149e2" |
||||
}, |
||||
"base": { |
||||
"xERC20": "0x2552516453368e42705D791F674b312b8b87CD9e" |
||||
}, |
||||
"blast": { |
||||
"xERC20": "0x486b39378f99f073A3043C6Aabe8666876A8F3C5" |
||||
}, |
||||
"bsc": { |
||||
"xERC20": "0xE00C6185a5c19219F1FFeD213b4406a254968c26" |
||||
}, |
||||
"mode": { |
||||
"xERC20": "0xC59336D8edDa9722B4f1Ec104007191Ec16f7087" |
||||
}, |
||||
"linea": { |
||||
"xERC20": "0xC59336D8edDa9722B4f1Ec104007191Ec16f7087" |
||||
}, |
||||
"ethereum": { |
||||
"xERC20Lockbox": "0xC59336D8edDa9722B4f1Ec104007191Ec16f7087" |
||||
}, |
||||
"fraxtal": { |
||||
"xERC20": "0x3aE8635A4D581d40a6Edfb3f2ED480f9532994F5" |
||||
}, |
||||
"zircuit": { |
||||
"xERC20": "0x2552516453368e42705D791F674b312b8b87CD9e" |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue