diff --git a/.changeset/dirty-clocks-repeat.md b/.changeset/dirty-clocks-repeat.md deleted file mode 100644 index d9159825a..000000000 --- a/.changeset/dirty-clocks-repeat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/utils': patch ---- - -Fix objMerge implementation diff --git a/.changeset/dirty-months-buy.md b/.changeset/dirty-months-buy.md deleted file mode 100644 index 2b3f91e99..000000000 --- a/.changeset/dirty-months-buy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/sdk': minor ---- - -Deploy to odysseytestnet diff --git a/.changeset/dry-foxes-battle.md b/.changeset/dry-foxes-battle.md deleted file mode 100644 index eadb8427e..000000000 --- a/.changeset/dry-foxes-battle.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@hyperlane-xyz/cli': minor ---- - -Add strategyUrl detect and validation in the beginning of `warp apply` -Remove yaml transactions print from `warp apply` diff --git a/.changeset/few-goats-add.md b/.changeset/few-goats-add.md deleted file mode 100644 index ffcab1f49..000000000 --- a/.changeset/few-goats-add.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/sdk': minor ---- - -Enroll new validators. Add tx overrides when deploying ICA accounts. Core checker now surfaces owner violations for defaultHook and requiredHook. App checker temporarily ignores bytecode mismatch violations. diff --git a/.changeset/fluffy-ducks-buy.md b/.changeset/fluffy-ducks-buy.md deleted file mode 100644 index 1b5db5097..000000000 --- a/.changeset/fluffy-ducks-buy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/sdk': minor ---- - -Add override to some transactions to fix warp apply diff --git a/.changeset/grumpy-ears-relate.md b/.changeset/grumpy-ears-relate.md deleted file mode 100644 index 8dbc0a515..000000000 --- a/.changeset/grumpy-ears-relate.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@hyperlane-xyz/cli': minor -'@hyperlane-xyz/sdk': minor ---- - -Adds the warp check command to compare warp routes config files with on chain warp route deployments diff --git a/.changeset/itchy-bananas-know.md b/.changeset/itchy-bananas-know.md new file mode 100644 index 000000000..188981756 --- /dev/null +++ b/.changeset/itchy-bananas-know.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/core': patch +--- + +Add wrapped HypERC4626 for easy defi use diff --git a/.changeset/itchy-singers-hang.md b/.changeset/itchy-singers-hang.md deleted file mode 100644 index 97096ff1a..000000000 --- a/.changeset/itchy-singers-hang.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/core': patch ---- - -Patched OPL2ToL1Ism to check for correct messageId for external call in verify diff --git a/.changeset/long-swans-drive.md b/.changeset/long-swans-drive.md deleted file mode 100644 index 3f21e56c4..000000000 --- a/.changeset/long-swans-drive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/cli': minor ---- - -Add prompt in `warp init` command to choose if a trusted relayer should be used instead of making the choice by default for the user and enable the `--yes` flag to default to a trusted ISM diff --git a/.changeset/perfect-dryers-destroy.md b/.changeset/perfect-dryers-destroy.md new file mode 100644 index 000000000..f9a906ef1 --- /dev/null +++ b/.changeset/perfect-dryers-destroy.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/core': minor +--- + +Minor token related changes like adding custom hook to 4626 collateral, checking for ERC20 as valid contract in HypERC20Collateral, etc. diff --git a/.changeset/plenty-chicken-clean.md b/.changeset/plenty-chicken-clean.md deleted file mode 100644 index e35a59eff..000000000 --- a/.changeset/plenty-chicken-clean.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@hyperlane-xyz/cli': minor -'@hyperlane-xyz/sdk': minor ---- - -Add rebasing yield route support into CLI/SDK diff --git a/.changeset/poor-coins-accept.md b/.changeset/poor-coins-accept.md deleted file mode 100644 index 2c3c6a892..000000000 --- a/.changeset/poor-coins-accept.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@hyperlane-xyz/helloworld': patch -'@hyperlane-xyz/widgets': patch -'@hyperlane-xyz/cli': patch ---- - -Update registry to v4.7.0 diff --git a/.changeset/red-actors-shop.md b/.changeset/red-actors-shop.md deleted file mode 100644 index 0ee301e90..000000000 --- a/.changeset/red-actors-shop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/core': patch ---- - -Added nonce to HypERC4626 diff --git a/.changeset/shiny-baboons-hunt.md b/.changeset/shiny-baboons-hunt.md new file mode 100644 index 000000000..ef302d93f --- /dev/null +++ b/.changeset/shiny-baboons-hunt.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/core': minor +--- + +Added WHypERC4626 as a wrapper for rebasing HypERC4626 diff --git a/.changeset/silver-dancers-rhyme.md b/.changeset/silver-dancers-rhyme.md deleted file mode 100644 index 14ce7dd00..000000000 --- a/.changeset/silver-dancers-rhyme.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/infra': minor ---- - -Updates the warpIds for Renzo's latest deployment to Sei and Taiko to be used by the Checker diff --git a/.changeset/sweet-humans-argue.md b/.changeset/sweet-humans-argue.md deleted file mode 100644 index 3a6ff4647..000000000 --- a/.changeset/sweet-humans-argue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/core': minor ---- - -Added PRECISION and rateUpdateNonce to ensure compatibility of HypERC4626 diff --git a/.changeset/tender-spiders-deny.md b/.changeset/tender-spiders-deny.md deleted file mode 100644 index 99a6cede4..000000000 --- a/.changeset/tender-spiders-deny.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/cli': minor ---- - -Update `warp apply` such that it updates in place AND extends in a single call diff --git a/.changeset/tidy-hornets-beam.md b/.changeset/tidy-hornets-beam.md deleted file mode 100644 index b4cff7c2f..000000000 --- a/.changeset/tidy-hornets-beam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/sdk': minor ---- - -Add deployments for mainnets: flow, metall2, polynomial diff --git a/.changeset/tricky-mangos-sin.md b/.changeset/tricky-mangos-sin.md deleted file mode 100644 index 31ea11b57..000000000 --- a/.changeset/tricky-mangos-sin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/cli': minor ---- - -updates the multi chain selection prompt by adding search functionality and an optional confirmation prompt for the current selection diff --git a/.changeset/wise-camels-repair.md b/.changeset/wise-camels-repair.md deleted file mode 100644 index 7cde52ed6..000000000 --- a/.changeset/wise-camels-repair.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@hyperlane-xyz/sdk': patch ---- - -Set transaction overrides and add 10% gas limit buffer when sending message through HyperlaneCore. diff --git a/.github/actions/yarn-build-with-cache/action.yml b/.github/actions/yarn-build-with-cache/action.yml index 7ffad99a0..2aec33acc 100644 --- a/.github/actions/yarn-build-with-cache/action.yml +++ b/.github/actions/yarn-build-with-cache/action.yml @@ -11,12 +11,26 @@ runs: steps: - name: Cache uses: buildjet/cache@v4 + id: cache with: path: | **/node_modules .yarn key: ${{ runner.os }}-yarn-cache-${{ hashFiles('./yarn.lock') }} - fail-on-cache-miss: true + + # Typically, the cache will be hit, but if there's a network error when + # restoring the cache, let's run the install step ourselves. + - name: Install dependencies + if: steps.cache.outputs.cache-hit != 'true' + shell: bash + run: | + yarn install + CHANGES=$(git status -s --ignore-submodules) + if [[ ! -z $CHANGES ]]; then + echo "Changes found: $CHANGES" + git diff + exit 1 + fi - name: Build shell: bash diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b37075002..bfbb3c8f6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -109,6 +109,30 @@ jobs: - name: Unit Tests run: yarn test:ci + cli-e2e: + runs-on: ubuntu-latest + needs: [yarn-install] + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + submodules: recursive + fetch-depth: 0 + + - name: foundry-install + uses: foundry-rs/foundry-toolchain@v1 + + - name: yarn-build + uses: ./.github/actions/yarn-build-with-cache + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Checkout registry + uses: ./.github/actions/checkout-registry + + - name: CLI e2e tests + run: yarn --cwd typescript/cli test:e2e + agent-configs: runs-on: ubuntu-latest needs: [yarn-install] @@ -218,7 +242,7 @@ jobs: run: | if [[ -n "$(git diff ${{ github.event.pull_request.head.sha || github.sha }} ${{ github.event.pull_request.base.sha }} -- ./rust)" ]]; then echo "rust_changes=true" >> $GITHUB_OUTPUT - echo "$(git diff ${{ github.event.pull_request.head.sha || github.sha }} ${{ github.event.pull_request.base.sha }} -- ./rust)" + echo "$(git diff ${{ github.event.pull_request.head.sha || github.sha }} ${{ github.event.pull_request.base.sha }} -- ./rust)" else echo "rust_changes=false" >> $GITHUB_OUTPUT fi diff --git a/.registryrc b/.registryrc index 44edec0c4..862c96776 100644 --- a/.registryrc +++ b/.registryrc @@ -1 +1 @@ -8583d0841615313c8c880e765eba760378e061cd +dee58183e51f4eb43e84dbac0e595a4b389dbe80 diff --git a/rust/main/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs b/rust/main/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs index 80dcfc622..3a89e313d 100644 --- a/rust/main/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs +++ b/rust/main/agents/scraper/migration/src/m20230309_000001_create_table_domain.rs @@ -438,6 +438,14 @@ const DOMAINS: &[RawDomain] = &[ is_test_net: false, is_deprecated: false, }, + RawDomain { + name: "stride", + token: "STRD", + domain: 745, + chain_id: 745, + is_test_net: false, + is_deprecated: false, + }, RawDomain { name: "cosmostest99990", token: "OSMO", diff --git a/rust/main/agents/validator/src/settings.rs b/rust/main/agents/validator/src/settings.rs index 02dc87cb1..d464be5a9 100644 --- a/rust/main/agents/validator/src/settings.rs +++ b/rust/main/agents/validator/src/settings.rs @@ -15,7 +15,9 @@ use hyperlane_base::{ CheckpointSyncerConf, Settings, SignerConf, }, }; -use hyperlane_core::{cfg_unwrap_all, config::*, HyperlaneDomain, HyperlaneDomainProtocol}; +use hyperlane_core::{ + cfg_unwrap_all, config::*, HyperlaneDomain, HyperlaneDomainProtocol, ReorgPeriod, +}; use serde::Deserialize; use serde_json::Value; @@ -36,8 +38,8 @@ pub struct ValidatorSettings { pub validator: SignerConf, /// The checkpoint syncer configuration pub checkpoint_syncer: CheckpointSyncerConf, - /// The reorg_period in blocks - pub reorg_period: u64, + /// The reorg configuration + pub reorg_period: ReorgPeriod, /// How frequently to check for new checkpoints pub interval: Duration, } @@ -122,8 +124,8 @@ impl FromRawConf for ValidatorSettings { .get_key(origin_chain_name) .get_opt_key("blocks") .get_opt_key("reorgPeriod") - .parse_u64() - .unwrap_or(1); + .parse_value("Invalid reorgPeriod") + .unwrap_or(ReorgPeriod::from_blocks(1)); cfg_unwrap_all!(cwp, err: [base, origin_chain, validator, checkpoint_syncer]); diff --git a/rust/main/agents/validator/src/submit.rs b/rust/main/agents/validator/src/submit.rs index 94d596467..954b8d0d9 100644 --- a/rust/main/agents/validator/src/submit.rs +++ b/rust/main/agents/validator/src/submit.rs @@ -1,4 +1,3 @@ -use std::num::NonZeroU64; use std::sync::Arc; use std::time::{Duration, Instant}; use std::vec; @@ -14,13 +13,13 @@ use hyperlane_core::{ accumulator::incremental::IncrementalMerkle, Checkpoint, CheckpointWithMessageId, HyperlaneChain, HyperlaneContract, HyperlaneDomain, HyperlaneSignerExt, }; -use hyperlane_core::{ChainResult, MerkleTreeHook, ReorgEvent}; +use hyperlane_core::{ChainResult, MerkleTreeHook, ReorgEvent, ReorgPeriod}; use hyperlane_ethereum::SingletonSignerHandle; #[derive(Clone)] pub(crate) struct ValidatorSubmitter { interval: Duration, - reorg_period: Option, + reorg_period: ReorgPeriod, signer: SingletonSignerHandle, merkle_tree_hook: Arc, checkpoint_syncer: Arc, @@ -31,7 +30,7 @@ pub(crate) struct ValidatorSubmitter { impl ValidatorSubmitter { pub(crate) fn new( interval: Duration, - reorg_period: u64, + reorg_period: ReorgPeriod, merkle_tree_hook: Arc, signer: SingletonSignerHandle, checkpoint_syncer: Arc, @@ -39,7 +38,7 @@ impl ValidatorSubmitter { metrics: ValidatorSubmitterMetrics, ) -> Self { Self { - reorg_period: NonZeroU64::new(reorg_period), + reorg_period, interval, merkle_tree_hook, signer, @@ -94,7 +93,8 @@ impl ValidatorSubmitter { // Lag by reorg period because this is our correctness checkpoint. let latest_checkpoint = call_and_retry_indefinitely(|| { let merkle_tree_hook = self.merkle_tree_hook.clone(); - Box::pin(async move { merkle_tree_hook.latest_checkpoint(self.reorg_period).await }) + let reorg_period = self.reorg_period.clone(); + Box::pin(async move { merkle_tree_hook.latest_checkpoint(&reorg_period).await }) }) .await; @@ -211,7 +211,7 @@ impl ValidatorSubmitter { correctness_checkpoint.root, checkpoint.index, chrono::Utc::now().timestamp() as u64, - self.reorg_period.map(|x| x.get()).unwrap_or(0), + self.reorg_period.clone(), ); error!( ?checkpoint, @@ -486,9 +486,9 @@ mod test { #[async_trait] impl MerkleTreeHook for MerkleTreeHook { - async fn tree(&self, lag: Option) -> ChainResult; - async fn count(&self, lag: Option) -> ChainResult; - async fn latest_checkpoint(&self, lag: Option) -> ChainResult; + async fn tree(&self, reorg_period: &ReorgPeriod) -> ChainResult; + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult; + async fn latest_checkpoint(&self, reorg_period: &ReorgPeriod) -> ChainResult; } } @@ -532,7 +532,7 @@ mod test { expected_local_merkle_tree: &IncrementalMerkle, mock_onchain_merkle_tree: &IncrementalMerkle, unix_timestamp: u64, - expected_reorg_period: u64, + expected_reorg_period: ReorgPeriod, ) { assert_eq!( reorg_event.canonical_merkle_root, @@ -617,7 +617,7 @@ mod test { &expected_local_merkle_tree, &mock_onchain_merkle_tree_clone, unix_timestamp, - expected_reorg_period, + ReorgPeriod::from_blocks(expected_reorg_period), ); Ok(()) }); @@ -625,7 +625,7 @@ mod test { // instantiate the validator submitter let validator_submitter = ValidatorSubmitter::new( Duration::from_secs(1), - expected_reorg_period, + ReorgPeriod::from_blocks(expected_reorg_period), Arc::new(mock_merkle_tree_hook), dummy_singleton_handle(), Arc::new(mock_checkpoint_syncer), diff --git a/rust/main/agents/validator/src/validator.rs b/rust/main/agents/validator/src/validator.rs index 31fe809b4..2d09bd93f 100644 --- a/rust/main/agents/validator/src/validator.rs +++ b/rust/main/agents/validator/src/validator.rs @@ -1,4 +1,4 @@ -use std::{num::NonZeroU64, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; use crate::server as validator_server; use async_trait::async_trait; @@ -19,8 +19,8 @@ use hyperlane_base::{ use hyperlane_core::{ Announcement, ChainResult, HyperlaneChain, HyperlaneContract, HyperlaneDomain, HyperlaneSigner, - HyperlaneSignerExt, Mailbox, MerkleTreeHook, MerkleTreeInsertion, TxOutcome, ValidatorAnnounce, - H256, U256, + HyperlaneSignerExt, Mailbox, MerkleTreeHook, MerkleTreeInsertion, ReorgPeriod, TxOutcome, + ValidatorAnnounce, H256, U256, }; use hyperlane_ethereum::{SingletonSigner, SingletonSignerHandle}; @@ -44,7 +44,7 @@ pub struct Validator { signer: SingletonSignerHandle, // temporary holder until `run` is called signer_instance: Option>, - reorg_period: u64, + reorg_period: ReorgPeriod, interval: Duration, checkpoint_syncer: Arc, core_metrics: Arc, @@ -184,12 +184,10 @@ impl BaseAgent for Validator { // announce the validator after spawning the signer task self.announce().await.expect("Failed to announce validator"); - let reorg_period = NonZeroU64::new(self.reorg_period); - // Ensure that the merkle tree hook has count > 0 before we begin indexing // messages or submitting checkpoints. loop { - match self.merkle_tree_hook.count(reorg_period).await { + match self.merkle_tree_hook.count(&self.reorg_period).await { Ok(0) => { info!("Waiting for first message in merkle tree hook"); sleep(self.interval).await; @@ -241,7 +239,7 @@ impl Validator { async fn run_checkpoint_submitters(&self) -> Vec>> { let submitter = ValidatorSubmitter::new( self.interval, - self.reorg_period, + self.reorg_period.clone(), self.merkle_tree_hook.clone(), self.signer.clone(), self.checkpoint_syncer.clone(), @@ -249,10 +247,9 @@ impl Validator { ValidatorSubmitterMetrics::new(&self.core.metrics, &self.origin_chain), ); - let reorg_period = NonZeroU64::new(self.reorg_period); let tip_tree = self .merkle_tree_hook - .tree(reorg_period) + .tree(&self.reorg_period) .await .expect("failed to get merkle tree"); // This function is only called after we have already checked that the diff --git a/rust/main/chains/hyperlane-cosmos/src/mailbox/contract.rs b/rust/main/chains/hyperlane-cosmos/src/mailbox/contract.rs index 9c793c93e..5a998aac5 100644 --- a/rust/main/chains/hyperlane-cosmos/src/mailbox/contract.rs +++ b/rust/main/chains/hyperlane-cosmos/src/mailbox/contract.rs @@ -8,7 +8,7 @@ use tracing::instrument; use hyperlane_core::{ utils::bytes_to_hex, ChainResult, ContractLocator, HyperlaneChain, HyperlaneContract, HyperlaneDomain, HyperlaneMessage, HyperlaneProvider, Mailbox, RawHyperlaneMessage, - TxCostEstimate, TxOutcome, H256, U256, + ReorgPeriod, TxCostEstimate, TxOutcome, H256, U256, }; use crate::grpc::WasmProvider; @@ -17,7 +17,7 @@ use crate::payloads::mailbox::{ GeneralMailboxQuery, ProcessMessageRequest, ProcessMessageRequestInner, }; use crate::types::tx_response_to_outcome; -use crate::utils::get_block_height_for_lag; +use crate::utils::get_block_height_for_reorg_period; use crate::{payloads, ConnectionConf, CosmosAddress, CosmosProvider, Signer}; #[derive(Clone, Debug)] @@ -82,8 +82,9 @@ impl HyperlaneChain for CosmosMailbox { impl Mailbox for CosmosMailbox { #[instrument(level = "debug", err, ret, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue - async fn count(&self, lag: Option) -> ChainResult { - let block_height = get_block_height_for_lag(self.provider.grpc(), lag).await?; + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult { + let block_height = + get_block_height_for_reorg_period(self.provider.grpc(), reorg_period).await?; self.nonce_at_block(block_height).await } diff --git a/rust/main/chains/hyperlane-cosmos/src/merkle_tree_hook.rs b/rust/main/chains/hyperlane-cosmos/src/merkle_tree_hook.rs index c9e48c59f..b9acdd357 100644 --- a/rust/main/chains/hyperlane-cosmos/src/merkle_tree_hook.rs +++ b/rust/main/chains/hyperlane-cosmos/src/merkle_tree_hook.rs @@ -10,15 +10,15 @@ use hyperlane_core::accumulator::incremental::IncrementalMerkle; use hyperlane_core::{ ChainCommunicationError, ChainResult, Checkpoint, ContractLocator, HyperlaneChain, HyperlaneContract, HyperlaneDomain, HyperlaneProvider, Indexed, Indexer, LogMeta, - MerkleTreeHook, MerkleTreeInsertion, SequenceAwareIndexer, H256, H512, + MerkleTreeHook, MerkleTreeInsertion, ReorgPeriod, SequenceAwareIndexer, H256, H512, }; use crate::grpc::WasmProvider; use crate::payloads::{general, merkle_tree_hook}; use crate::rpc::{CosmosWasmRpcProvider, ParsedEvent, WasmRpcProvider}; use crate::utils::{ - execute_and_parse_log_futures, get_block_height_for_lag, parse_logs_in_range, parse_logs_in_tx, - CONTRACT_ADDRESS_ATTRIBUTE_KEY, CONTRACT_ADDRESS_ATTRIBUTE_KEY_BASE64, + execute_and_parse_log_futures, get_block_height_for_reorg_period, parse_logs_in_range, + parse_logs_in_tx, CONTRACT_ADDRESS_ATTRIBUTE_KEY, CONTRACT_ADDRESS_ATTRIBUTE_KEY_BASE64, }; use crate::{ConnectionConf, CosmosProvider, HyperlaneCosmosError, Signer}; @@ -76,12 +76,13 @@ impl MerkleTreeHook for CosmosMerkleTreeHook { /// Return the incremental merkle tree in storage #[instrument(level = "debug", err, ret, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue - async fn tree(&self, lag: Option) -> ChainResult { + async fn tree(&self, reorg_period: &ReorgPeriod) -> ChainResult { let payload = merkle_tree_hook::MerkleTreeRequest { tree: general::EmptyStruct {}, }; - let block_height = get_block_height_for_lag(self.provider.grpc(), lag).await?; + let block_height = + get_block_height_for_reorg_period(self.provider.grpc(), reorg_period).await?; let data = self .provider @@ -110,23 +111,26 @@ impl MerkleTreeHook for CosmosMerkleTreeHook { } /// Gets the current leaf count of the merkle tree - async fn count(&self, lag: Option) -> ChainResult { + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult { let payload = merkle_tree_hook::MerkleTreeCountRequest { count: general::EmptyStruct {}, }; - let block_height = get_block_height_for_lag(self.provider.grpc(), lag).await?; + let block_height = + get_block_height_for_reorg_period(self.provider.grpc(), reorg_period).await?; self.count_at_block(block_height).await } + #[instrument(level = "debug", err, ret, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue - async fn latest_checkpoint(&self, lag: Option) -> ChainResult { + async fn latest_checkpoint(&self, reorg_period: &ReorgPeriod) -> ChainResult { let payload = merkle_tree_hook::CheckPointRequest { check_point: general::EmptyStruct {}, }; - let block_height = get_block_height_for_lag(self.provider.grpc(), lag).await?; + let block_height = + get_block_height_for_reorg_period(self.provider.grpc(), reorg_period).await?; let data = self .provider diff --git a/rust/main/chains/hyperlane-cosmos/src/utils.rs b/rust/main/chains/hyperlane-cosmos/src/utils.rs index 74cb75a27..f792090e6 100644 --- a/rust/main/chains/hyperlane-cosmos/src/utils.rs +++ b/rust/main/chains/hyperlane-cosmos/src/utils.rs @@ -11,7 +11,7 @@ use tendermint::Hash; use tokio::task::JoinHandle; use tracing::warn; -use hyperlane_core::{ChainCommunicationError, ChainResult, Indexed, LogMeta, H256}; +use hyperlane_core::{ChainCommunicationError, ChainResult, Indexed, LogMeta, ReorgPeriod, H256}; use crate::grpc::{WasmGrpcProvider, WasmProvider}; use crate::rpc::{CosmosWasmRpcProvider, ParsedEvent, WasmRpcProvider}; @@ -24,20 +24,25 @@ pub(crate) const CONTRACT_ADDRESS_ATTRIBUTE_KEY: &str = "_contract_address"; pub(crate) static CONTRACT_ADDRESS_ATTRIBUTE_KEY_BASE64: Lazy = Lazy::new(|| BASE64.encode(CONTRACT_ADDRESS_ATTRIBUTE_KEY)); -/// Given a lag, returns the block height at the moment. -/// If the lag is None, a block height of None is given, indicating that the -/// tip directly can be used. -pub(crate) async fn get_block_height_for_lag( +/// Given a `reorg_period`, returns the block height at the moment. +/// If the `reorg_period` is None, a block height of None is given, +/// indicating that the tip directly can be used. +pub(crate) async fn get_block_height_for_reorg_period( provider: &WasmGrpcProvider, - lag: Option, + reorg_period: &ReorgPeriod, ) -> ChainResult> { - let block_height = match lag { - Some(lag) => { + let block_height = match reorg_period { + ReorgPeriod::Blocks(blocks) => { let tip = provider.latest_block_height().await?; - let block_height = tip - lag.get(); + let block_height = tip - blocks.get() as u64; Some(block_height) } - None => None, + ReorgPeriod::None => None, + ReorgPeriod::Tag(_) => { + return Err(ChainCommunicationError::InvalidReorgPeriod( + reorg_period.clone(), + )) + } }; Ok(block_height) diff --git a/rust/main/chains/hyperlane-ethereum/src/config.rs b/rust/main/chains/hyperlane-ethereum/src/config.rs index 8735b5fd2..e1375e790 100644 --- a/rust/main/chains/hyperlane-ethereum/src/config.rs +++ b/rust/main/chains/hyperlane-ethereum/src/config.rs @@ -1,4 +1,8 @@ -use hyperlane_core::{config::OperationBatchConfig, U256}; +use ethers::providers::Middleware; +use ethers_core::types::{BlockId, BlockNumber}; +use hyperlane_core::{ + config::OperationBatchConfig, ChainCommunicationError, ChainResult, ReorgPeriod, U256, +}; use url::Url; /// Ethereum RPC connection configuration @@ -52,3 +56,51 @@ pub struct TransactionOverrides { /// Max priority fee per gas to use for EIP-1559 transactions. pub max_priority_fee_per_gas: Option, } + +/// Ethereum reorg period +#[derive(Copy, Clone, Debug)] +pub enum EthereumReorgPeriod { + /// Number of blocks + Blocks(u32), + /// A block tag + Tag(BlockId), +} + +impl TryFrom<&ReorgPeriod> for EthereumReorgPeriod { + type Error = ChainCommunicationError; + + fn try_from(value: &ReorgPeriod) -> Result { + match value { + ReorgPeriod::None => Ok(EthereumReorgPeriod::Blocks(0)), + ReorgPeriod::Blocks(blocks) => Ok(EthereumReorgPeriod::Blocks(blocks.get())), + ReorgPeriod::Tag(tag) => { + let tag = match tag.as_str() { + "latest" => BlockNumber::Latest, + "finalized" => BlockNumber::Finalized, + "safe" => BlockNumber::Safe, + "earliest" => BlockNumber::Earliest, + "pending" => BlockNumber::Pending, + _ => return Err(ChainCommunicationError::InvalidReorgPeriod(value.clone())), + }; + Ok(EthereumReorgPeriod::Tag(tag.into())) + } + } + } +} + +impl EthereumReorgPeriod { + /// Converts the reorg period into a block id + pub async fn into_block_id( + &self, + provider: &M, + ) -> ChainResult { + let block_id = match self { + EthereumReorgPeriod::Blocks(_) => { + (crate::get_finalized_block_number(provider, self).await? as u64).into() + } + // no need to fetch the block number for the `tag` + EthereumReorgPeriod::Tag(tag) => *tag, + }; + Ok(block_id) + } +} diff --git a/rust/main/chains/hyperlane-ethereum/src/contracts/interchain_gas.rs b/rust/main/chains/hyperlane-ethereum/src/contracts/interchain_gas.rs index b14903a64..d7cf37e81 100644 --- a/rust/main/chains/hyperlane-ethereum/src/contracts/interchain_gas.rs +++ b/rust/main/chains/hyperlane-ethereum/src/contracts/interchain_gas.rs @@ -9,18 +9,18 @@ use async_trait::async_trait; use ethers::prelude::Middleware; use hyperlane_core::rpc_clients::call_and_retry_indefinitely; use hyperlane_core::{ - ChainCommunicationError, ChainResult, ContractLocator, HyperlaneAbi, HyperlaneChain, - HyperlaneContract, HyperlaneDomain, HyperlaneProvider, Indexed, Indexer, - InterchainGasPaymaster, InterchainGasPayment, LogMeta, SequenceAwareIndexer, H160, H256, H512, + ChainResult, ContractLocator, HyperlaneAbi, HyperlaneChain, HyperlaneContract, HyperlaneDomain, + HyperlaneProvider, Indexed, Indexer, InterchainGasPaymaster, InterchainGasPayment, LogMeta, + SequenceAwareIndexer, H160, H256, H512, }; use tracing::instrument; -use super::utils::fetch_raw_logs_and_meta; +use super::utils::{fetch_raw_logs_and_meta, get_finalized_block_number}; use crate::interfaces::i_interchain_gas_paymaster::{ GasPaymentFilter, IInterchainGasPaymaster as EthereumInterchainGasPaymasterInternal, IINTERCHAINGASPAYMASTER_ABI, }; -use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider, EthereumReorgPeriod}; impl Display for EthereumInterchainGasPaymasterInternal where @@ -33,7 +33,7 @@ where pub struct InterchainGasPaymasterIndexerBuilder { pub mailbox_address: H160, - pub reorg_period: u32, + pub reorg_period: EthereumReorgPeriod, } #[async_trait] @@ -63,7 +63,7 @@ where { contract: Arc>, provider: Arc, - reorg_period: u32, + reorg_period: EthereumReorgPeriod, } impl EthereumInterchainGasPaymasterIndexer @@ -71,7 +71,11 @@ where M: Middleware + 'static, { /// Create new EthereumInterchainGasPaymasterIndexer - pub fn new(provider: Arc, locator: &ContractLocator, reorg_period: u32) -> Self { + pub fn new( + provider: Arc, + locator: &ContractLocator, + reorg_period: EthereumReorgPeriod, + ) -> Self { Self { contract: Arc::new(EthereumInterchainGasPaymasterInternal::new( locator.address, @@ -122,13 +126,7 @@ where #[instrument(level = "debug", err, ret, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue async fn get_finalized_block_number(&self) -> ChainResult { - Ok(self - .provider - .get_block_number() - .await - .map_err(ChainCommunicationError::from_other)? - .as_u32() - .saturating_sub(self.reorg_period)) + get_finalized_block_number(&self.provider, &self.reorg_period).await } async fn fetch_logs_by_tx_hash( diff --git a/rust/main/chains/hyperlane-ethereum/src/contracts/mailbox.rs b/rust/main/chains/hyperlane-ethereum/src/contracts/mailbox.rs index 72d01e4d6..a9141e7b7 100644 --- a/rust/main/chains/hyperlane-ethereum/src/contracts/mailbox.rs +++ b/rust/main/chains/hyperlane-ethereum/src/contracts/mailbox.rs @@ -2,7 +2,6 @@ #![allow(missing_docs)] use std::collections::HashMap; -use std::num::NonZeroU64; use std::ops::RangeInclusive; use std::sync::Arc; @@ -14,7 +13,7 @@ use ethers_contract::builders::ContractCall; use ethers_contract::{Multicall, MulticallResult}; use futures_util::future::join_all; use hyperlane_core::rpc_clients::call_and_retry_indefinitely; -use hyperlane_core::{BatchResult, QueueOperation, H512}; +use hyperlane_core::{BatchResult, QueueOperation, ReorgPeriod, H512}; use itertools::Itertools; use tracing::instrument; @@ -31,11 +30,14 @@ use crate::interfaces::i_mailbox::{ IMailbox as EthereumMailboxInternal, ProcessCall, IMAILBOX_ABI, }; use crate::interfaces::mailbox::DispatchFilter; -use crate::tx::{call_with_lag, fill_tx_gas_params, report_tx}; -use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider, TransactionOverrides}; +use crate::tx::{call_with_reorg_period, fill_tx_gas_params, report_tx}; +use crate::{ + BuildableWithProvider, ConnectionConf, EthereumProvider, EthereumReorgPeriod, + TransactionOverrides, +}; use super::multicall::{self, build_multicall}; -use super::utils::fetch_raw_logs_and_meta; +use super::utils::{fetch_raw_logs_and_meta, get_finalized_block_number}; impl std::fmt::Display for EthereumMailboxInternal where @@ -47,7 +49,7 @@ where } pub struct SequenceIndexerBuilder { - pub reorg_period: u32, + pub reorg_period: EthereumReorgPeriod, } #[async_trait] @@ -70,7 +72,7 @@ impl BuildableWithProvider for SequenceIndexerBuilder { } pub struct DeliveryIndexerBuilder { - pub reorg_period: u32, + pub reorg_period: EthereumReorgPeriod, } #[async_trait] @@ -100,7 +102,7 @@ where { contract: Arc>, provider: Arc, - reorg_period: u32, + reorg_period: EthereumReorgPeriod, } impl EthereumMailboxIndexer @@ -108,7 +110,11 @@ where M: Middleware + 'static, { /// Create new EthereumMailboxIndexer - pub fn new(provider: Arc, locator: &ContractLocator, reorg_period: u32) -> Self { + pub fn new( + provider: Arc, + locator: &ContractLocator, + reorg_period: EthereumReorgPeriod, + ) -> Self { let contract = Arc::new(EthereumMailboxInternal::new( locator.address, provider.clone(), @@ -122,13 +128,7 @@ where #[instrument(level = "debug", err, ret, skip(self))] async fn get_finalized_block_number(&self) -> ChainResult { - Ok(self - .provider - .get_block_number() - .await - .map_err(ChainCommunicationError::from_other)? - .as_u32() - .saturating_sub(self.reorg_period)) + get_finalized_block_number(&self.provider, &self.reorg_period).await } } @@ -460,8 +460,9 @@ where M: Middleware + 'static, { #[instrument(skip(self))] - async fn count(&self, maybe_lag: Option) -> ChainResult { - let call = call_with_lag(self.contract.nonce(), &self.provider, maybe_lag).await?; + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult { + let call = + call_with_reorg_period(self.contract.nonce(), &self.provider, reorg_period).await?; let nonce = call.call().await?; Ok(nonce) } diff --git a/rust/main/chains/hyperlane-ethereum/src/contracts/merkle_tree_hook.rs b/rust/main/chains/hyperlane-ethereum/src/contracts/merkle_tree_hook.rs index a2f8a4a74..f098d75ca 100644 --- a/rust/main/chains/hyperlane-ethereum/src/contracts/merkle_tree_hook.rs +++ b/rust/main/chains/hyperlane-ethereum/src/contracts/merkle_tree_hook.rs @@ -1,5 +1,4 @@ #![allow(missing_docs)] -use std::num::NonZeroU64; use std::ops::RangeInclusive; use std::sync::Arc; @@ -10,18 +9,18 @@ use hyperlane_core::rpc_clients::call_and_retry_indefinitely; use tracing::instrument; use hyperlane_core::{ - ChainCommunicationError, ChainResult, Checkpoint, ContractLocator, HyperlaneChain, - HyperlaneContract, HyperlaneDomain, HyperlaneProvider, Indexed, Indexer, LogMeta, - MerkleTreeHook, MerkleTreeInsertion, SequenceAwareIndexer, H256, H512, + ChainResult, Checkpoint, ContractLocator, HyperlaneChain, HyperlaneContract, HyperlaneDomain, + HyperlaneProvider, Indexed, Indexer, LogMeta, MerkleTreeHook, MerkleTreeInsertion, ReorgPeriod, + SequenceAwareIndexer, H256, H512, }; use crate::interfaces::merkle_tree_hook::{ InsertedIntoTreeFilter, MerkleTreeHook as MerkleTreeHookContract, Tree, }; -use crate::tx::call_with_lag; -use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; +use crate::tx::call_with_reorg_period; +use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider, EthereumReorgPeriod}; -use super::utils::fetch_raw_logs_and_meta; +use super::utils::{fetch_raw_logs_and_meta, get_finalized_block_number}; // We don't need the reverse of this impl, so it's ok to disable the clippy lint #[allow(clippy::from_over_into)] @@ -58,7 +57,7 @@ impl BuildableWithProvider for MerkleTreeHookBuilder { } pub struct MerkleTreeHookIndexerBuilder { - pub reorg_period: u32, + pub reorg_period: EthereumReorgPeriod, } #[async_trait] @@ -88,7 +87,7 @@ where { contract: Arc>, provider: Arc, - reorg_period: u32, + reorg_period: EthereumReorgPeriod, } impl EthereumMerkleTreeHookIndexer @@ -96,7 +95,11 @@ where M: Middleware + 'static, { /// Create new EthereumMerkleTreeHookIndexer - pub fn new(provider: Arc, locator: &ContractLocator, reorg_period: u32) -> Self { + pub fn new( + provider: Arc, + locator: &ContractLocator, + reorg_period: EthereumReorgPeriod, + ) -> Self { Self { contract: Arc::new(MerkleTreeHookContract::new( locator.address, @@ -143,13 +146,7 @@ where #[instrument(level = "debug", err, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue async fn get_finalized_block_number(&self) -> ChainResult { - Ok(self - .provider - .get_block_number() - .await - .map_err(ChainCommunicationError::from_other)? - .as_u32() - .saturating_sub(self.reorg_period)) + get_finalized_block_number(&self.provider, &self.reorg_period).await } async fn fetch_logs_by_tx_hash( @@ -253,9 +250,13 @@ where M: Middleware + 'static, { #[instrument(skip(self))] - async fn latest_checkpoint(&self, maybe_lag: Option) -> ChainResult { - let call = - call_with_lag(self.contract.latest_checkpoint(), &self.provider, maybe_lag).await?; + async fn latest_checkpoint(&self, reorg_period: &ReorgPeriod) -> ChainResult { + let call = call_with_reorg_period( + self.contract.latest_checkpoint(), + &self.provider, + reorg_period, + ) + .await?; let (root, index) = call.call().await?; Ok(Checkpoint { @@ -268,15 +269,17 @@ where #[instrument(skip(self))] #[allow(clippy::needless_range_loop)] - async fn tree(&self, maybe_lag: Option) -> ChainResult { - let call = call_with_lag(self.contract.tree(), &self.provider, maybe_lag).await?; + async fn tree(&self, reorg_period: &ReorgPeriod) -> ChainResult { + let call = + call_with_reorg_period(self.contract.tree(), &self.provider, reorg_period).await?; Ok(call.call().await?.into()) } #[instrument(skip(self))] - async fn count(&self, maybe_lag: Option) -> ChainResult { - let call = call_with_lag(self.contract.count(), &self.provider, maybe_lag).await?; + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult { + let call = + call_with_reorg_period(self.contract.count(), &self.provider, reorg_period).await?; let count = call.call().await?; Ok(count) } diff --git a/rust/main/chains/hyperlane-ethereum/src/contracts/mod.rs b/rust/main/chains/hyperlane-ethereum/src/contracts/mod.rs index 1a39fae07..f8475f9e7 100644 --- a/rust/main/chains/hyperlane-ethereum/src/contracts/mod.rs +++ b/rust/main/chains/hyperlane-ethereum/src/contracts/mod.rs @@ -1,5 +1,7 @@ pub use {interchain_gas::*, mailbox::*, merkle_tree_hook::*, validator_announce::*}; +pub(crate) use utils::get_finalized_block_number; + mod interchain_gas; mod mailbox; mod merkle_tree_hook; diff --git a/rust/main/chains/hyperlane-ethereum/src/contracts/utils.rs b/rust/main/chains/hyperlane-ethereum/src/contracts/utils.rs index 290519918..5e9c78201 100644 --- a/rust/main/chains/hyperlane-ethereum/src/contracts/utils.rs +++ b/rust/main/chains/hyperlane-ethereum/src/contracts/utils.rs @@ -6,7 +6,10 @@ use ethers::{ types::{H160 as EthersH160, H256 as EthersH256}, }; use ethers_contract::{ContractError, EthEvent, LogMeta as EthersLogMeta}; -use hyperlane_core::{ChainResult, LogMeta, H512}; +use hyperlane_core::{ChainCommunicationError, ChainResult, LogMeta, H512}; +use tracing::instrument; + +use crate::EthereumReorgPeriod; pub async fn fetch_raw_logs_and_meta( tx_hash: H512, @@ -44,3 +47,33 @@ where .collect(); Ok(logs) } + +#[instrument(level = "trace", err, ret, skip(provider))] +pub async fn get_finalized_block_number( + provider: &M, + reorg_period: &EthereumReorgPeriod, +) -> ChainResult +where + M: Middleware + 'static, +{ + let number = match *reorg_period { + EthereumReorgPeriod::Blocks(blocks) => provider + .get_block_number() + .await + .map_err(ChainCommunicationError::from_other)? + .as_u32() + .saturating_sub(blocks), + + EthereumReorgPeriod::Tag(tag) => provider + .get_block(tag) + .await + .map_err(ChainCommunicationError::from_other)? + .and_then(|block| block.number) + .ok_or(ChainCommunicationError::CustomError( + "Unable to get finalized block number".into(), + ))? + .as_u32(), + }; + + Ok(number) +} diff --git a/rust/main/chains/hyperlane-ethereum/src/tx.rs b/rust/main/chains/hyperlane-ethereum/src/tx.rs index eb42f66d4..05cc4da44 100644 --- a/rust/main/chains/hyperlane-ethereum/src/tx.rs +++ b/rust/main/chains/hyperlane-ethereum/src/tx.rs @@ -1,4 +1,3 @@ -use std::num::NonZeroU64; use std::sync::Arc; use std::time::Duration; @@ -16,10 +15,12 @@ use ethers_core::{ EIP1559_FEE_ESTIMATION_REWARD_PERCENTILE, }, }; -use hyperlane_core::{utils::bytes_to_hex, ChainCommunicationError, ChainResult, H256, U256}; +use hyperlane_core::{ + utils::bytes_to_hex, ChainCommunicationError, ChainResult, ReorgPeriod, H256, U256, +}; use tracing::{debug, error, info, warn}; -use crate::{Middleware, TransactionOverrides}; +use crate::{EthereumReorgPeriod, Middleware, TransactionOverrides}; /// An amount of gas to add to the estimated gas pub const GAS_ESTIMATE_BUFFER: u32 = 75_000; @@ -216,23 +217,20 @@ where Ok((base_fee_per_gas, max_fee_per_gas, max_priority_fee_per_gas)) } -pub(crate) async fn call_with_lag( +pub(crate) async fn call_with_reorg_period( call: ethers::contract::builders::ContractCall, provider: &M, - maybe_lag: Option, + reorg_period: &ReorgPeriod, ) -> ChainResult> where M: Middleware + 'static, T: Detokenize, { - if let Some(lag) = maybe_lag { - let fixed_block_number: BlockNumber = provider - .get_block_number() - .await - .map_err(ChainCommunicationError::from_other)? - .saturating_sub(lag.get().into()) - .into(); - Ok(call.block(fixed_block_number)) + if !reorg_period.is_none() { + let block_id = EthereumReorgPeriod::try_from(reorg_period)? + .into_block_id(provider) + .await?; + Ok(call.block(block_id)) } else { Ok(call) } diff --git a/rust/main/chains/hyperlane-fuel/src/mailbox.rs b/rust/main/chains/hyperlane-fuel/src/mailbox.rs index 1c78e839e..fbe951abe 100644 --- a/rust/main/chains/hyperlane-fuel/src/mailbox.rs +++ b/rust/main/chains/hyperlane-fuel/src/mailbox.rs @@ -10,13 +10,12 @@ use fuels::{ use hyperlane_core::{ utils::bytes_to_hex, ChainCommunicationError, ChainResult, ContractLocator, HyperlaneAbi, HyperlaneChain, HyperlaneContract, HyperlaneDomain, HyperlaneMessage, HyperlaneProvider, - Indexed, Indexer, LogMeta, Mailbox, RawHyperlaneMessage, SequenceAwareIndexer, TxCostEstimate, - TxOutcome, H256, H512, U256, + Indexed, Indexer, LogMeta, Mailbox, RawHyperlaneMessage, ReorgPeriod, SequenceAwareIndexer, + TxCostEstimate, TxOutcome, H256, H512, U256, }; use std::{ collections::HashMap, fmt::{Debug, Formatter}, - num::NonZeroU64, ops::RangeInclusive, }; use tracing::{instrument, warn}; @@ -74,9 +73,9 @@ impl Debug for FuelMailbox { impl Mailbox for FuelMailbox { #[instrument(level = "debug", err, ret, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue - async fn count(&self, lag: Option) -> ChainResult { + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult { assert!( - lag.is_none(), + reorg_period.is_none(), "Fuel does not support querying point-in-time" ); self.contract diff --git a/rust/main/chains/hyperlane-sealevel/src/mailbox.rs b/rust/main/chains/hyperlane-sealevel/src/mailbox.rs index 952599c42..5453360e0 100644 --- a/rust/main/chains/hyperlane-sealevel/src/mailbox.rs +++ b/rust/main/chains/hyperlane-sealevel/src/mailbox.rs @@ -12,8 +12,8 @@ use hyperlane_core::{ ChainCommunicationError::ContractError, ChainResult, Checkpoint, ContractLocator, Decode as _, Encode as _, FixedPointNumber, HyperlaneAbi, HyperlaneChain, HyperlaneContract, HyperlaneDomain, HyperlaneMessage, HyperlaneProvider, Indexed, Indexer, KnownHyperlaneDomain, - LogMeta, Mailbox, MerkleTreeHook, SequenceAwareIndexer, TxCostEstimate, TxOutcome, H256, H512, - U256, + LogMeta, Mailbox, MerkleTreeHook, ReorgPeriod, SequenceAwareIndexer, TxCostEstimate, TxOutcome, + H256, H512, U256, }; use hyperlane_sealevel_interchain_security_module_interface::{ InterchainSecurityModuleInstruction, VerifyInstruction, @@ -416,8 +416,8 @@ impl std::fmt::Debug for SealevelMailbox { #[async_trait] impl Mailbox for SealevelMailbox { #[instrument(err, ret, skip(self))] - async fn count(&self, _maybe_lag: Option) -> ChainResult { - ::count(self, _maybe_lag).await + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult { + ::count(self, reorg_period).await } #[instrument(err, ret, skip(self))] @@ -755,7 +755,7 @@ impl SequenceAwareIndexer for SealevelMailboxIndexer { async fn latest_sequence_count_and_tip(&self) -> ChainResult<(Option, u32)> { let tip = Indexer::::get_finalized_block_number(self).await?; // TODO: need to make sure the call and tip are at the same height? - let count = Mailbox::count(&self.mailbox, None).await?; + let count = Mailbox::count(&self.mailbox, &ReorgPeriod::None).await?; Ok((Some(count), tip)) } } diff --git a/rust/main/chains/hyperlane-sealevel/src/merkle_tree_hook.rs b/rust/main/chains/hyperlane-sealevel/src/merkle_tree_hook.rs index 947f7e70a..a0813bfba 100644 --- a/rust/main/chains/hyperlane-sealevel/src/merkle_tree_hook.rs +++ b/rust/main/chains/hyperlane-sealevel/src/merkle_tree_hook.rs @@ -1,11 +1,11 @@ -use std::{num::NonZeroU64, ops::RangeInclusive}; +use std::ops::RangeInclusive; use async_trait::async_trait; use derive_new::new; use hyperlane_core::{ accumulator::incremental::IncrementalMerkle, ChainCommunicationError, ChainResult, Checkpoint, HyperlaneChain, HyperlaneMessage, Indexed, Indexer, LogMeta, MerkleTreeHook, - MerkleTreeInsertion, SequenceAwareIndexer, + MerkleTreeInsertion, ReorgPeriod, SequenceAwareIndexer, }; use hyperlane_sealevel_mailbox::accounts::OutboxAccount; use tracing::instrument; @@ -16,9 +16,9 @@ use crate::{SealevelMailbox, SealevelMailboxIndexer}; impl MerkleTreeHook for SealevelMailbox { #[instrument(err, ret, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue - async fn tree(&self, lag: Option) -> ChainResult { + async fn tree(&self, reorg_period: &ReorgPeriod) -> ChainResult { assert!( - lag.is_none(), + reorg_period.is_none(), "Sealevel does not support querying point-in-time" ); @@ -35,13 +35,13 @@ impl MerkleTreeHook for SealevelMailbox { #[instrument(err, ret, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue - async fn latest_checkpoint(&self, lag: Option) -> ChainResult { + async fn latest_checkpoint(&self, reorg_period: &ReorgPeriod) -> ChainResult { assert!( - lag.is_none(), + reorg_period.is_none(), "Sealevel does not support querying point-in-time" ); - let tree = self.tree(lag).await?; + let tree = self.tree(reorg_period).await?; let root = tree.root(); let count: u32 = tree @@ -64,8 +64,8 @@ impl MerkleTreeHook for SealevelMailbox { #[instrument(err, ret, skip(self))] #[allow(clippy::blocks_in_conditions)] // TODO: `rustc` 1.80.1 clippy issue - async fn count(&self, _maybe_lag: Option) -> ChainResult { - let tree = self.tree(_maybe_lag).await?; + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult { + let tree = self.tree(reorg_period).await?; tree.count() .try_into() diff --git a/rust/main/config/mainnet_config.json b/rust/main/config/mainnet_config.json index 2667590fe..a562cd84e 100644 --- a/rust/main/config/mainnet_config.json +++ b/rust/main/config/mainnet_config.json @@ -34,7 +34,7 @@ "interchainAccountIsm": "0xd766e7C7517f2d0D92754b2fe4aE7AdEf7bDEC3e", "interchainAccountRouter": "0x25C87e735021F72d8728438C2130b02E3141f2cb", "interchainGasPaymaster": "0x8F1E22d309baa69D398a03cc88E9b46037e988AA", - "interchainSecurityModule": "0x565C280Cdb56095Cf6BF23b5fF140180208CBa9e", + "interchainSecurityModule": "0x4e1d2cdB48A2C2912b11801Eb1F1d5007474cA43", "isTestnet": false, "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0x811808Dd29ba8B0FC6C0ec0b5537035E59745162", @@ -100,7 +100,7 @@ "interchainAccountIsm": "0x2A7574358Ec53522CE2452887661AB4c86F7d400", "interchainAccountRouter": "0x91874Dbed74925dFe6059B90385EEb90DdE0B2E6", "interchainGasPaymaster": "0x3b6044acd6767f017e99318AA6Ef93b7B06A5a22", - "interchainSecurityModule": "0x3d0BE14dFbB1Eb736303260c1724B6ea270c8Dc4", + "interchainSecurityModule": "0x50d0b0E27B8B93119618f053A623886116dd3b6d", "mailbox": "0x979Ca5202784112f4738403dBec5D0F3B9daabB9", "merkleTreeHook": "0x748040afB89B8FdBb992799808215419d36A0930", "name": "arbitrum", @@ -172,7 +172,7 @@ "interchainAccountIsm": "0x27a3233c05C1Df7c163123301D14bE9349E3Cb48", "interchainAccountRouter": "0xa82a0227e6d6db53AF4B264A852bfF91C6504a51", "interchainGasPaymaster": "0x95519ba800BBd0d34eeAE026fEc620AD978176C0", - "interchainSecurityModule": "0x6723A49c12FE37ccBD08512dd586C8471743676f", + "interchainSecurityModule": "0xbc803Da34A88E5f6B50dfc0CC9D924d9865c91C5", "mailbox": "0xFf06aFcaABaDDd1fb08371f9ccA15D73D51FeBD6", "merkleTreeHook": "0x84eea61D679F42D92145fA052C89900CBAccE95A", "name": "avalanche", @@ -245,7 +245,7 @@ "interchainAccountIsm": "0x223F7D3f27E6272266AE4B5B91Fd5C7A2d798cD8", "interchainAccountRouter": "0x4767D22117bBeeb295413000B620B93FD8522d53", "interchainGasPaymaster": "0xc3F23848Ed2e04C0c6d41bd7804fa8f89F940B94", - "interchainSecurityModule": "0xaeEf8f7D049C03181E0B5f2746CA2Db4d25C0B82", + "interchainSecurityModule": "0xB7fcb4665ace2B0d36fd92D26b4a8B516c0bFe5F", "mailbox": "0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D", "merkleTreeHook": "0x19dc38aeae620380430C200a6E990D5Af5480117", "name": "base", @@ -316,7 +316,7 @@ "interchainAccountIsm": "0xe93f2f409ad8B5000431D234472973fe848dcBEC", "interchainAccountRouter": "0x2f4Eb04189e11Af642237Da62d163Ab714614498", "interchainGasPaymaster": "0xB3fCcD379ad66CED0c91028520C64226611A48c9", - "interchainSecurityModule": "0xbCe3469E8C270e04ea9ccd20Efdeed2b90c9d57C", + "interchainSecurityModule": "0xECa4a584E91867a72cd036DB7Db22Ad894a197B7", "mailbox": "0x3a867fCfFeC2B790970eeBDC9023E75B0a172aa7", "merkleTreeHook": "0xC9B8ea6230d6687a4b13fD3C0b8f0Ec607B26465", "name": "blast", @@ -384,7 +384,7 @@ "interchainAccountIsm": "0x451dF8AB0936D85526D816f0b4dCaDD934A034A4", "interchainAccountRouter": "0x5C02157068a52cEcfc98EDb6115DE6134EcB4764", "interchainGasPaymaster": "0x62B7592C1B6D1E43f4630B8e37f4377097840C05", - "interchainSecurityModule": "0x26eA240CB4cABd7B75A9F17E7f4e224170270Ee3", + "interchainSecurityModule": "0x93E3e6CA295803417212421785606B1F7dDeaD8f", "mailbox": "0x8358D8291e3bEDb04804975eEa0fe9fe0fAfB147", "merkleTreeHook": "0x781bE492F1232E66990d83a9D3AC3Ec26f56DAfB", "name": "bob", @@ -450,7 +450,7 @@ "interchainAccountIsm": "0x9e22945bE593946618383B108CC5bce09eBA4C26", "interchainAccountRouter": "0x32A07c1B7a7fe8D4A0e44B0181873aB9d64C16c1", "interchainGasPaymaster": "0x78E25e7f84416e69b9339B0A6336EB6EFfF6b451", - "interchainSecurityModule": "0x0A7cE15E3cc638abC3B5FfA7Fc8F3295Ae3595D1", + "interchainSecurityModule": "0xA0506B5b12770494740A4a7cc86C9A36Dc1Fc6Dc", "mailbox": "0x2971b9Aec44bE4eb673DF1B88cDB57b96eefe8a4", "merkleTreeHook": "0xFDb9Cd5f9daAA2E4474019405A328a88E7484f26", "name": "bsc", @@ -531,7 +531,7 @@ "interchainAccountIsm": "0xB732c83aeE29596E3163Da2260710eAB67Bc0B29", "interchainAccountRouter": "0x27a6cAe33378bB6A6663b382070427A01fc9cB37", "interchainGasPaymaster": "0x571f1435613381208477ac5d6974310d88AC7cB7", - "interchainSecurityModule": "0x33BC62504248F4cb43813532067ccAEd46a5e61C", + "interchainSecurityModule": "0xa6f4835940dbA46E295076D0CD0411349C33789f", "mailbox": "0x50da3B3907A08a24fe4999F4Dcf337E8dC7954bb", "merkleTreeHook": "0x04dB778f05854f26E67e0a66b740BBbE9070D366", "name": "celo", @@ -596,7 +596,7 @@ "interchainAccountIsm": "0x4Eb82Ee35b0a1c1d776E3a3B547f9A9bA6FCC9f2", "interchainAccountRouter": "0xEF9A332Ec1fD233Bf9344A58be56ff9E104B4f60", "interchainGasPaymaster": "0x7E27456a839BFF31CA642c060a2b68414Cb6e503", - "interchainSecurityModule": "0xc1FF2bf7a4C315bE2a06941D236457EB02F93993", + "interchainSecurityModule": "0x05f6BAa16F1aCf7b19c4A09E019D856c10ab8355", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0x0054D19613f20dD72721A146ED408971a2CCA9BD", "name": "cheesechain", @@ -659,7 +659,7 @@ "from": 4842212 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0xEfFaEddFf4FFd6F8a6D714bf149b114fD34E5Fd4", + "interchainSecurityModule": "0x9A746C4BC2bE7E657A3469f0a0DAA1dE517b8514", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "cyber", @@ -726,7 +726,7 @@ "from": 23783929 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0xB5e6AA45E117f9fD2a3F8e78432fCAfdB833d316", + "interchainSecurityModule": "0x168E9C1481F50E66Cc5F5E24b04eBf7071629c4E", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "degenchain", @@ -784,7 +784,8 @@ "gasCurrencyCoinGeckoId": "ethereum", "index": { "from": 1, - "mode": "sequence" + "mode": "sequence", + "chunk": 100 }, "interchainGasPaymaster": "ABb3i11z7wKoGCfeRQNQbVYWjAm7jG7HzZnDLV4RKRbK", "mailbox": "EitxJuv2iBjsg2d7jVy2LDC1e2zBrx4GB5Y9h2Ko3A9Y", @@ -838,7 +839,7 @@ "interchainAccountIsm": "0xCeafc098e5c3c7768b9229Be2FEC275862A81Abd", "interchainAccountRouter": "0xed9a722c543883FB7e07E78F3879762DE09eA7D5", "interchainGasPaymaster": "0xB30EAB08aa87138D57168D0e236850A530f49921", - "interchainSecurityModule": "0xC0737f1EA1d0aF287c2804090370b1715c593385", + "interchainSecurityModule": "0x094120BaC576aD7D88ec6893C9B220a0e64923E9", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xC831271c1fB212012811a91Dd43e5926C1020563", "name": "endurance", @@ -909,7 +910,7 @@ "interchainAccountIsm": "0x292C614ED53DaaDBf971521bc2C652d1ca51cB47", "interchainAccountRouter": "0x5E532F7B610618eE73C2B462978e94CB1F7995Ce", "interchainGasPaymaster": "0x9e6B1022bE9BBF5aFd152483DAD9b88911bC8611", - "interchainSecurityModule": "0xFc440a9c946Bf4840623E4adf49646089361584a", + "interchainSecurityModule": "0x23d160e4474Ce011829c71Bf1bCaA40F0b5612D5", "mailbox": "0xc005dc82818d67AF737725bD4bf75435d065D239", "merkleTreeHook": "0x48e6c30B97748d1e2e03bf3e9FbE3890ca5f8CCA", "name": "ethereum", @@ -978,7 +979,7 @@ "interchainAccountIsm": "0x7C012DCA02C42cfA3Fd7Da3B0ED7234B52AE68eF", "interchainAccountRouter": "0xbed53B5C5BCE9433f25A2A702e6df13E22d84Ae9", "interchainGasPaymaster": "0x2Fca7f6eC3d4A0408900f2BB30004d4616eE985E", - "interchainSecurityModule": "0x2bed66bbfE45f1d73928179e72B73e5eCF7B9900", + "interchainSecurityModule": "0x8B497dff421844Bb0882E0C495d0851D4461675C", "mailbox": "0x2f9DB5616fa3fAd1aB06cB2C906830BA63d135e3", "merkleTreeHook": "0x8358D8291e3bEDb04804975eEa0fe9fe0fAfB147", "name": "fraxtal", @@ -1046,7 +1047,7 @@ "interchainAccountIsm": "0x9629c28990F11c31735765A6FD59E1E1bC197DbD", "interchainAccountRouter": "0x2351FBe24C1212F253b7a300ff0cBCFd97952a19", "interchainGasPaymaster": "0xFB9e40D811Cea562cc8a322b029eF2BDcC3ef6ed", - "interchainSecurityModule": "0x1E12bdb6a33442102FEF2ab766b93c863653B4bE", + "interchainSecurityModule": "0x69b33D67B9C51D45E23d22E727FF186DD6298ECA", "mailbox": "0x3071D4DA6020C956Fe15Bfd0a9Ca8D4574f16696", "merkleTreeHook": "0xfBc08389224d23b79cb21cDc16c5d42F0ad0F57f", "name": "fusemainnet", @@ -1120,7 +1121,7 @@ "interchainAccountIsm": "0x07E2062A1bC66a2C1d05cb5C3870a4AF86e0056E", "interchainAccountRouter": "0xBE70Ab882D1F7E37e04a70CDd9Ec23b37a234064", "interchainGasPaymaster": "0xDd260B99d302f0A3fF885728c086f729c06f227f", - "interchainSecurityModule": "0x996Be332325DA49Ea590A9772a515d62dD90C74c", + "interchainSecurityModule": "0x00533a5F14B3a0632C86f99E4e20a10b73C4AE0D", "mailbox": "0xaD09d78f4c6b9dA2Ae82b1D34107802d380Bb74f", "merkleTreeHook": "0x2684C6F89E901987E1FdB7649dC5Be0c57C61645", "name": "gnosis", @@ -1183,7 +1184,7 @@ "domainId": 2525, "domainRoutingIsm": "0xBD70Ea9D599a0FC8158B026797177773C3445730", "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", - "fallbackRoutingHook": "0xA376b27212D608324808923Add679A2c9FAFe9Da", + "fallbackRoutingHook": "0xf8dba46ff9d8ef650052c89ca2df793fabc375f9", "gasCurrencyCoinGeckoId": "injective-protocol", "index": { "from": 37 @@ -1191,7 +1192,7 @@ "interchainAccountIsm": "0x708E002637792FDC031E6B62f23DD60014AC976a", "interchainAccountRouter": "0xfB8cea1c7F45608Da30655b50bbF355D123A4358", "interchainGasPaymaster": "0x19dc38aeae620380430C200a6E990D5Af5480117", - "interchainSecurityModule": "0x1Bff27a1c1319b0704348895b67426a4Eb1b629e", + "interchainSecurityModule": "0xB8F85B879775adF156Dd4AFa43e97DeB880d99D4", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0x0972954923a1e2b2aAb04Fa0c4a0797e5989Cd65", "name": "inevm", @@ -1228,7 +1229,14 @@ }, "injective": { "bech32Prefix": "inj", - "blockExplorers": [], + "blockExplorers": [ + { + "apiUrl": "https://www.mintscan.io/injective", + "family": "other", + "name": "Mintscan", + "url": "https://www.mintscan.io/injective" + } + ], "blocks": { "confirmations": 1, "estimateBlockTime": 1, @@ -1312,7 +1320,7 @@ "from": 14616307 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0xcaE599dD2142CD8F09a68bAC89b4d809A038d2E9", + "interchainSecurityModule": "0xE2968dAb74541184Ad95651b1e5Cf34Ab1bBEc97", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "kroma", @@ -1385,7 +1393,7 @@ "interchainAccountIsm": "0xdcA646C56E7768DD11654956adE24bfFf9Ba4893", "interchainAccountRouter": "0xD59dA396F162Ed93a41252Cebb8d5DD4F093238C", "interchainGasPaymaster": "0x8105a095368f1a184CceA86cCe21318B5Ee5BE28", - "interchainSecurityModule": "0x916e612358dA3F7E8e19f51ba2Cf7af3285a6793", + "interchainSecurityModule": "0x0EEF1e64646EE01DeED4850074Cd4B97C0A630a9", "mailbox": "0x02d16BC51af6BfD153d67CA61754cF912E82C4d9", "merkleTreeHook": "0xC077A0Cc408173349b1c9870C667B40FE3C01dd7", "name": "linea", @@ -1456,7 +1464,7 @@ "from": 4195553 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0xa660FA2047105E0341b356393218586ED2191d14", + "interchainSecurityModule": "0x63Bb509b9CA644609B15Ea55E56f0Acbbb9dB02E", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "lisk", @@ -1520,7 +1528,7 @@ "from": 3088760 }, "interchainGasPaymaster": "0x441a01Fca2eD731C0Fc4633998332f9FEDB17575", - "interchainSecurityModule": "0x391BD8dD2709F77d39dab4fB3bf4BCAfd5EC3248", + "interchainSecurityModule": "0x609ad94304896607A6D81DB00d882245045B79da", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0x062200d92dF6bB7bA89Ce4D6800110450f94784e", "name": "lukso", @@ -1594,7 +1602,7 @@ "interchainAccountIsm": "0x8Ea50255C282F89d1A14ad3F159437EE5EF0507f", "interchainAccountRouter": "0x693A4cE39d99e46B04cb562329e3F0141cA17331", "interchainGasPaymaster": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", - "interchainSecurityModule": "0xBcB96842301c659B575c40C3f93F7311D09c93d9", + "interchainSecurityModule": "0xC012e8E3cBeB6295E1E4837FBA5DB8E077EBc549", "isTestnet": false, "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x149db7afD694722747035d5AEC7007ccb6F8f112", @@ -1664,7 +1672,7 @@ "interchainAccountIsm": "0xe039DA3A0071BEd087A12660D7b03cf669c7776E", "interchainAccountRouter": "0x45285463352c53a481e882cD5E2AF2E25BBdAd0D", "interchainGasPaymaster": "0x8105a095368f1a184CceA86cCe21318B5Ee5BE28", - "interchainSecurityModule": "0xe542Ed13B5782aF0AFAe7f232bB867FB0208Ab7B", + "interchainSecurityModule": "0x8722328A5Ed815965F9B5eBAA21d04f0F9BFDd35", "mailbox": "0x398633D19f4371e1DB5a8EFE90468eB70B1176AA", "merkleTreeHook": "0x5332D1AC0A626D265298c14ff681c0A8D28dB86d", "name": "mantle", @@ -1726,7 +1734,7 @@ "from": 13523607 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0x5725a9Bf3bdaF104Ce1A0098308DD974F6395365", + "interchainSecurityModule": "0xE8176Fc70f129255aA83d3db242C2246Ad77Af7D", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "merlin", @@ -1793,7 +1801,7 @@ "from": 17966274 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0xfd810678075502F76A6ef79cedffe58cff6Cc410", + "interchainSecurityModule": "0xA9309228762699D5c81A4b0BAfd06Da21589746b", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "metis", @@ -1858,7 +1866,7 @@ "from": 3752032 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0xfd810678075502F76A6ef79cedffe58cff6Cc410", + "interchainSecurityModule": "0xA9309228762699D5c81A4b0BAfd06Da21589746b", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "mint", @@ -1925,7 +1933,7 @@ "interchainAccountIsm": "0xa377b8269e0A47cdd2fD5AAeAe860b45623c6d82", "interchainAccountRouter": "0x6e1B9f776bd415d7cC3C7458A5f0d801016918f8", "interchainGasPaymaster": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", - "interchainSecurityModule": "0x1ab6985E0e15d293e71d01510fa6B57311C69718", + "interchainSecurityModule": "0x0777dFffcEd18EE416e35401E0e5e0413b7D43be", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xE2ee936bEa8e42671c400aC96dE198E06F2bA2A6", "name": "mode", @@ -1993,7 +2001,7 @@ "interchainAccountIsm": "0x79b3730CE3685f65802aF1771319992bA960EB9D", "interchainAccountRouter": "0xc4482f66191754a8629D35289043C4EB0285F10E", "interchainGasPaymaster": "0x14760E32C0746094cF14D97124865BC7F0F7368F", - "interchainSecurityModule": "0x105215D46F45a88B3793B798Fb87AF231Ad9f611", + "interchainSecurityModule": "0xad1Ad827035eDe500aFd0ff122c53f6eA607Eb5C", "mailbox": "0x094d03E751f49908080EFf000Dd6FD177fd44CC3", "merkleTreeHook": "0x87403b85f6f316e7ba91ba1fa6C3Fb7dD4095547", "name": "moonbeam", @@ -2135,7 +2143,7 @@ "interchainAccountIsm": "0x2c46BF14641d00549ECa4779BF5CBf91602C1DEd", "interchainAccountRouter": "0x03D6cC17d45E9EA27ED757A8214d1F07F7D901aD", "interchainGasPaymaster": "0xD8A76C4D91fCbB7Cc8eA795DFDF870E48368995C", - "interchainSecurityModule": "0x1E491c93Ab56A298bBC34B4Fca8A4cE68E8d540a", + "interchainSecurityModule": "0x3878aB31B2426A92E8a1E0AE758d848879F7F5E8", "mailbox": "0xd4C1905BB1D26BC93DAC913e13CaCC278CdCC80D", "merkleTreeHook": "0x68eE9bec9B4dbB61f69D9D293Ae26a5AACb2e28f", "name": "optimism", @@ -2270,7 +2278,7 @@ "interchainAccountIsm": "0xBAC4529cdfE7CCe9E858BF706e41F8Ed096C1BAd", "interchainAccountRouter": "0xF163949AD9F88977ebF649D0461398Ca752E64B9", "interchainGasPaymaster": "0x0071740Bf129b05C4684abfbBeD248D80971cce2", - "interchainSecurityModule": "0x0D408EF040ca0E7a75f03c41Aa46cAc904770D45", + "interchainSecurityModule": "0x9fFC02BfB5C7260C985b005C0cF40d7EC601aac2", "mailbox": "0x5d934f4e2f797775e53561bB72aca21ba36B96BB", "merkleTreeHook": "0x73FbD25c3e817DC4B4Cd9d00eff6D83dcde2DfF6", "name": "polygon", @@ -2347,7 +2355,7 @@ "interchainAccountIsm": "0xc1198e241DAe48BF5AEDE5DCE49Fe4A6064cF7a7", "interchainAccountRouter": "0x20a0A32a110362920597F72974E1E0d7e25cA20a", "interchainGasPaymaster": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", - "interchainSecurityModule": "0x5C622f40365F57D06b5e7132B1483fcbc9566560", + "interchainSecurityModule": "0xc6c475184F197FA65f233dFc22FA6bD4cE48B4fE", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x149db7afD694722747035d5AEC7007ccb6F8f112", "name": "polygonzkevm", @@ -2415,7 +2423,7 @@ "from": 32018468 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0x336306ADB3c510A318107c01D109D2072c7abB6B", + "interchainSecurityModule": "0x70e8beCE806914959c1B5D8F75d2217058D31437", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "proofofplay", @@ -2479,7 +2487,7 @@ "from": 363159 }, "interchainGasPaymaster": "0x3071D4DA6020C956Fe15Bfd0a9Ca8D4574f16696", - "interchainSecurityModule": "0x06567d07b49ad922A821A641F1C962569a255dbB", + "interchainSecurityModule": "0x43346a54445BBdf8241062904E8A13AA62842a02", "mailbox": "0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D", "merkleTreeHook": "0x55E4F0bc6b7Bb493D50839A8592e7ad8d5e93cf7", "name": "real", @@ -2546,7 +2554,7 @@ "interchainAccountIsm": "0x5DA60220C5dDe35b7aE91c042ff5979047FA0785", "interchainAccountRouter": "0x7a4d31a686A36285d68e14EDD53631417eB19603", "interchainGasPaymaster": "0x2Fa570E83009eaEef3a1cbd496a9a30F05266634", - "interchainSecurityModule": "0x5a3bB91853CfDaDb1bC95D2E061B50d433fbe3E8", + "interchainSecurityModule": "0xd8b6B632526834D8192860e6B6CE47165Fd02a42", "mailbox": "0xeA87ae93Fa0019a82A727bfd3eBd1cFCa8f64f1D", "merkleTreeHook": "0x8F1E22d309baa69D398a03cc88E9b46037e988AA", "name": "redstone", @@ -2608,7 +2616,7 @@ "from": 937117 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0xA76F4620ac1e97d273B2C9Ca71805c8afD792098", + "interchainSecurityModule": "0x6A2748201F66647ad6D164CB3340A893881A4bb2", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "sanko", @@ -2676,7 +2684,7 @@ "interchainAccountIsm": "0x32af5Df81fEd5E26119F6640FBB13f3d63a94CDe", "interchainAccountRouter": "0x0B48a744698ba8dFa514742dFEB6728f52fD66f7", "interchainGasPaymaster": "0xBF12ef4B9f307463D3FB59c3604F294dDCe287E2", - "interchainSecurityModule": "0x37e17723b665A9F95F4aecEEc40D9eF39624764e", + "interchainSecurityModule": "0xAd1a987BfE0D6fbD92089628daC7C7e4bA9a6AAF", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0x6119E37Bd66406A1Db74920aC79C15fB8411Ba76", "name": "scroll", @@ -2744,7 +2752,7 @@ "interchainAccountIsm": "0xf35dc7B9eE4Ebf0cd3546Bd6EE3b403dE2b9F5D6", "interchainAccountRouter": "0xBcaedE97a98573A88242B3b0CB0A255F3f90d4d5", "interchainGasPaymaster": "0xFC62DeF1f08793aBf0E67f69257c6be258194F72", - "interchainSecurityModule": "0x26184898fA27D3471B50BD956AB5b3E9Aa14763C", + "interchainSecurityModule": "0x494028EA206642e4c60Ec3d12e96B4549E5e1800", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xca1b69fA4c4a7c7fD839bC50867c589592bcfe49", "name": "sei", @@ -2804,7 +2812,8 @@ "gasCurrencyCoinGeckoId": "solana", "index": { "from": 1, - "mode": "sequence" + "mode": "sequence", + "chunk": 100 }, "interchainGasPaymaster": "JAvHW21tYXE9dtdG83DReqU2b4LUexFuCbtJT5tF8X6M", "mailbox": "E588QtVUvresuXq2KoNEwAmoifCzYGpRBdHByN9KQMbi", @@ -2858,7 +2867,7 @@ "interchainAccountIsm": "0xAE557e108b3336130370aC74836f1356B4b30Cf2", "interchainAccountRouter": "0x1F8CF09F060A2AE962c0Bb1F92e209a1E7b0E10B", "interchainGasPaymaster": "0x273Bc6b01D9E88c064b6E5e409BdF998246AEF42", - "interchainSecurityModule": "0x478D0e5d221C8d7CA1A6353315fac6FA88Ff1B97", + "interchainSecurityModule": "0xC93F2796A17Ee4580c039aeB7b0c923b10ce79C2", "mailbox": "0x28EFBCadA00A7ed6772b3666F3898d276e88CAe3", "merkleTreeHook": "0x6A55822cf11f9fcBc4c75BC2638AfE8Eb942cAdd", "name": "taiko", @@ -2920,7 +2929,7 @@ "from": 1678063 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0x336306ADB3c510A318107c01D109D2072c7abB6B", + "interchainSecurityModule": "0x70e8beCE806914959c1B5D8F75d2217058D31437", "isTestnet": false, "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", @@ -2988,7 +2997,7 @@ "interchainAccountIsm": "0x551BbEc45FD665a8C95ca8731CbC32b7653Bc59B", "interchainAccountRouter": "0xc11f8Cf2343d3788405582F65B8af6A4F7a6FfC8", "interchainGasPaymaster": "0x0D63128D887159d63De29497dfa45AFc7C699AE4", - "interchainSecurityModule": "0x5542503cBde841c336Afef014FE80b0F1c9d716d", + "interchainSecurityModule": "0x3465AccC39AE5e6C344184013a57cDCe546834d6", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0x149db7afD694722747035d5AEC7007ccb6F8f112", "name": "viction", @@ -3056,7 +3065,7 @@ "interchainAccountIsm": "0xCB9f90EE5d83Ea52ABd922BD70898f0155D54798", "interchainAccountRouter": "0x473884010F0C1742DA8Ad01E7E295624B931076b", "interchainGasPaymaster": "0x7E27456a839BFF31CA642c060a2b68414Cb6e503", - "interchainSecurityModule": "0xc1FF2bf7a4C315bE2a06941D236457EB02F93993", + "interchainSecurityModule": "0x05f6BAa16F1aCf7b19c4A09E019D856c10ab8355", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0x0054D19613f20dD72721A146ED408971a2CCA9BD", "name": "worldchain", @@ -3118,7 +3127,7 @@ "from": 24395308 }, "interchainGasPaymaster": "0x9844aFFaBE17c37F791ff99ABa58B0FbB75e22AF", - "interchainSecurityModule": "0xC630ef37e03534721557026FeC397Ec05f85584C", + "interchainSecurityModule": "0x4886ed96bcdba2ad85Bf518C3171C39e256ac840", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "name": "xai", @@ -3186,7 +3195,7 @@ "interchainAccountIsm": "0x29B37088724B745C0ABcE591449Cf042772160C2", "interchainAccountRouter": "0x03cF708E42C89623bd83B281A56935cB562b9258", "interchainGasPaymaster": "0x7E27456a839BFF31CA642c060a2b68414Cb6e503", - "interchainSecurityModule": "0x0811C6250965E7Ba1A872A12249B1b2300d85CFD", + "interchainSecurityModule": "0x59B0ec92522F164b72c9BE473382197c564B92dc", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0x0054D19613f20dD72721A146ED408971a2CCA9BD", "name": "xlayer", @@ -3254,7 +3263,7 @@ "interchainAccountIsm": "0x2b6d3F7d28B5EC8C3C028fBCAdcf774D9709Dd29", "interchainAccountRouter": "0x3AdCBc94ab8C48EC52D06dc65Bb787fD1981E3d5", "interchainGasPaymaster": "0x931dFCc8c1141D6F532FD023bd87DAe0080c835d", - "interchainSecurityModule": "0x858a077945bCC4afA40DaE5a75faB9237e899b30", + "interchainSecurityModule": "0xd32353Ae5719ac4f8f24AeD81A2A6898d2632D26", "mailbox": "0x2f2aFaE1139Ce54feFC03593FeE8AB2aDF4a85A7", "merkleTreeHook": "0xE2ee936bEa8e42671c400aC96dE198E06F2bA2A6", "name": "zetachain", @@ -3320,7 +3329,7 @@ "from": 1511458 }, "interchainGasPaymaster": "0x03cF708E42C89623bd83B281A56935cB562b9258", - "interchainSecurityModule": "0xb04DE6Cbc6E258E8f2D2B00EBdcD2Ea901791EAA", + "interchainSecurityModule": "0xFFec270FE3D0e3B9348B3664BE73A5d4906BA620", "mailbox": "0xc2FbB9411186AB3b1a6AFCCA702D1a80B48b197c", "merkleTreeHook": "0x4C97D35c668EE5194a13c8DE8Afc18cce40C9F28", "name": "zircuit", @@ -3393,7 +3402,7 @@ "interchainAccountIsm": "0xb2674E213019972f937CCFc5e23BF963D915809e", "interchainAccountRouter": "0x11b76D93a9D39Eb51F54eBf5566308640cDe882b", "interchainGasPaymaster": "0x18B0688990720103dB63559a3563f7E8d0f63EDb", - "interchainSecurityModule": "0xDede6e50E548460FB6a939320F707214CFfC701C", + "interchainSecurityModule": "0xED5fD1715A0885a3C7B908BAd5c8C64Ba5166265", "mailbox": "0xF5da68b2577EF5C0A0D98aA2a58483a68C2f232a", "merkleTreeHook": "0x886BB0f329781b98f98FDeb1ce7a8957F2d43B9F", "name": "zoramainnet", @@ -3464,7 +3473,7 @@ "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "fallbackRoutingHook": "0xc401e251CCa7A364114504A994D6fC7cb1c243AB", "interchainGasPaymaster": "0x4E55aDA3ef1942049EA43E904EB01F4A0a9c39bd", - "interchainSecurityModule": "0x2b19CEB3ef3B1D7428b0788d44401E44E381B62B", + "interchainSecurityModule": "0x8Ad4d573D7EafC4Ca58f1dB704B8Db804814D674", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x441a01Fca2eD731C0Fc4633998332f9FEDB17575", "pausableHook": "0x5Ed813B8b41f25c8002B01A72bbDBe6A0232Fe27", @@ -3531,7 +3540,7 @@ "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "fallbackRoutingHook": "0xc401e251CCa7A364114504A994D6fC7cb1c243AB", "interchainGasPaymaster": "0x4E55aDA3ef1942049EA43E904EB01F4A0a9c39bd", - "interchainSecurityModule": "0x8Ad4d573D7EafC4Ca58f1dB704B8Db804814D674", + "interchainSecurityModule": "0xa18979d2e5b8A64f62E0f9e9523d28E934F1104c", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x441a01Fca2eD731C0Fc4633998332f9FEDB17575", "pausableHook": "0x5Ed813B8b41f25c8002B01A72bbDBe6A0232Fe27", @@ -3601,7 +3610,7 @@ "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "fallbackRoutingHook": "0xc401e251CCa7A364114504A994D6fC7cb1c243AB", "interchainGasPaymaster": "0x4E55aDA3ef1942049EA43E904EB01F4A0a9c39bd", - "interchainSecurityModule": "0x2b19CEB3ef3B1D7428b0788d44401E44E381B62B", + "interchainSecurityModule": "0x8Ad4d573D7EafC4Ca58f1dB704B8Db804814D674", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x441a01Fca2eD731C0Fc4633998332f9FEDB17575", "pausableHook": "0x5Ed813B8b41f25c8002B01A72bbDBe6A0232Fe27", @@ -3677,7 +3686,7 @@ "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "fallbackRoutingHook": "0xc401e251CCa7A364114504A994D6fC7cb1c243AB", "interchainGasPaymaster": "0x4E55aDA3ef1942049EA43E904EB01F4A0a9c39bd", - "interchainSecurityModule": "0x2b19CEB3ef3B1D7428b0788d44401E44E381B62B", + "interchainSecurityModule": "0x8Ad4d573D7EafC4Ca58f1dB704B8Db804814D674", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x441a01Fca2eD731C0Fc4633998332f9FEDB17575", "pausableHook": "0x5Ed813B8b41f25c8002B01A72bbDBe6A0232Fe27", @@ -3741,7 +3750,7 @@ "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "fallbackRoutingHook": "0xc401e251CCa7A364114504A994D6fC7cb1c243AB", "interchainGasPaymaster": "0x4E55aDA3ef1942049EA43E904EB01F4A0a9c39bd", - "interchainSecurityModule": "0x2b19CEB3ef3B1D7428b0788d44401E44E381B62B", + "interchainSecurityModule": "0x8Ad4d573D7EafC4Ca58f1dB704B8Db804814D674", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x441a01Fca2eD731C0Fc4633998332f9FEDB17575", "pausableHook": "0x5Ed813B8b41f25c8002B01A72bbDBe6A0232Fe27", @@ -3814,7 +3823,7 @@ "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "fallbackRoutingHook": "0xc401e251CCa7A364114504A994D6fC7cb1c243AB", "interchainGasPaymaster": "0x4E55aDA3ef1942049EA43E904EB01F4A0a9c39bd", - "interchainSecurityModule": "0x2b19CEB3ef3B1D7428b0788d44401E44E381B62B", + "interchainSecurityModule": "0x8Ad4d573D7EafC4Ca58f1dB704B8Db804814D674", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x441a01Fca2eD731C0Fc4633998332f9FEDB17575", "pausableHook": "0x5Ed813B8b41f25c8002B01A72bbDBe6A0232Fe27", @@ -3882,7 +3891,7 @@ "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "fallbackRoutingHook": "0xc401e251CCa7A364114504A994D6fC7cb1c243AB", "interchainGasPaymaster": "0x4E55aDA3ef1942049EA43E904EB01F4A0a9c39bd", - "interchainSecurityModule": "0x2b19CEB3ef3B1D7428b0788d44401E44E381B62B", + "interchainSecurityModule": "0x8Ad4d573D7EafC4Ca58f1dB704B8Db804814D674", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x441a01Fca2eD731C0Fc4633998332f9FEDB17575", "pausableHook": "0x5Ed813B8b41f25c8002B01A72bbDBe6A0232Fe27", @@ -3945,7 +3954,7 @@ "domainRoutingIsmFactory": "0x1052eF3419f26Bec74Ed7CEf4a4FA6812Bc09908", "fallbackRoutingHook": "0xc401e251CCa7A364114504A994D6fC7cb1c243AB", "interchainGasPaymaster": "0x4E55aDA3ef1942049EA43E904EB01F4A0a9c39bd", - "interchainSecurityModule": "0x12C8cfA5B97Df96AaB2795a4186675dA49938968", + "interchainSecurityModule": "0xf08b7F859966ed27286Fe7d924A42b40e2DB80Bd", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x441a01Fca2eD731C0Fc4633998332f9FEDB17575", "pausableHook": "0x5Ed813B8b41f25c8002B01A72bbDBe6A0232Fe27", @@ -4015,7 +4024,7 @@ "interchainAccountIsm": "0xcd9D3744512F07AE844c40E27912092d7c503565", "interchainAccountRouter": "0x92cdbF0Ccdf8E93467FA858fb986fa650A02f2A8", "interchainGasPaymaster": "0xb58257cc81E47EC72fD38aE16297048de23163b4", - "interchainSecurityModule": "0xA16954f5040ba7fE2286569aD107a22a46FffDC6", + "interchainSecurityModule": "0xcC5C35a6214982d9018B95e9684D5b4dA626237e", "mailbox": "0x7f50C5776722630a0024fAE05fDe8b47571D7B39", "merkleTreeHook": "0xCC3D1659D50461d27a2F025dDb2c9B06B584B7e1", "pausableHook": "0x4E55aDA3ef1942049EA43E904EB01F4A0a9c39bd", @@ -4075,7 +4084,7 @@ "interchainAccountIsm": "0xc23BaF5Eb5848D19701BbE7f139645e6bd58a319", "interchainAccountRouter": "0x7c58Cadcc2b60ACF794eE1843488d6f5703f76BE", "interchainGasPaymaster": "0xb4fc9B5fD57499Ef6FfF3995728a55F7A618ef86", - "interchainSecurityModule": "0x128432015A0E08d490e0FD6b4dE4EAbe30f617a3", + "interchainSecurityModule": "0x50B5Edd94A1C7ad18Fa2CA667A30Dc051a695aEe", "mailbox": "0xb129828B9EDa48192D0B2db35D0E40dCF51B3594", "merkleTreeHook": "0x3E969bA938E6A993eeCD6F65b0dd8712B07dFe59", "pausableHook": "0x6Fb36672365C7c797028C400A61c58c0ECc53cD2", @@ -4147,7 +4156,7 @@ "interchainAccountIsm": "0x783EC5e105234a570eB90f314284E5dBe53bdd90", "interchainAccountRouter": "0xc5D6aCaafBCcEC6D7fD7d92F4509befce641c563", "interchainGasPaymaster": "0xe8d5590F2e969F9d21f0132f2b596273f8a03Ef2", - "interchainSecurityModule": "0xe274f228f87c0D72241CF9aAC15d91e3630aE6f6", + "interchainSecurityModule": "0x58D6fb4aADd3ae83ec529d3d0f42Ae904207a336", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0xDab56C5A1EffFdd23f6BD1243E457B1575984Bc6", "pausableHook": "0x73db9c7430548f399e335f3424e8d56080e9010c", @@ -4210,7 +4219,7 @@ "interchainAccountIsm": "0x9eaaC366BFD70430cFee6E70265fefFf1CfC9E47", "interchainAccountRouter": "0xbb0AE51BCa526cF313b6a95BfaB020794af6C394", "interchainGasPaymaster": "0xe8d5590F2e969F9d21f0132f2b596273f8a03Ef2", - "interchainSecurityModule": "0xe274f228f87c0D72241CF9aAC15d91e3630aE6f6", + "interchainSecurityModule": "0x58D6fb4aADd3ae83ec529d3d0f42Ae904207a336", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0xDab56C5A1EffFdd23f6BD1243E457B1575984Bc6", "pausableHook": "0x73db9c7430548f399e335f3424e8d56080e9010c", @@ -4280,7 +4289,7 @@ "interchainAccountIsm": "0xeE8C0E1EeBfFCC451a013336386eA53E42a44451", "interchainAccountRouter": "0x9eb56085DdbDA60aDf7d2B533AFeD90e38fC9666", "interchainGasPaymaster": "0xe8d5590F2e969F9d21f0132f2b596273f8a03Ef2", - "interchainSecurityModule": "0xe274f228f87c0D72241CF9aAC15d91e3630aE6f6", + "interchainSecurityModule": "0x58D6fb4aADd3ae83ec529d3d0f42Ae904207a336", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0xDab56C5A1EffFdd23f6BD1243E457B1575984Bc6", "pausableHook": "0x73db9c7430548f399e335f3424e8d56080e9010c", @@ -4351,7 +4360,7 @@ "interchainAccountIsm": "0x25EAC2007b0D40E3f0AF112FD346412321038719", "interchainAccountRouter": "0xfF26696DcDb6BbFD27e959b847D4f1399D5BcF64", "interchainGasPaymaster": "0x9024A3902B542C87a5C4A2b3e15d60B2f087Dc3E", - "interchainSecurityModule": "0x8750ac24C3bE28b406fBCD664AbabF676d3aCB29", + "interchainSecurityModule": "0x9dccF81bB9f419425b0a6584E8800556B92209Cc", "mailbox": "0x3a867fCfFeC2B790970eeBDC9023E75B0a172aa7", "merkleTreeHook": "0x9c44E6b8F0dB517C2c3a0478caaC5349b614F912", "pausableHook": "0x53e912b41125d6094590a7DBEf1360d3d56EEa19", @@ -4419,7 +4428,7 @@ "interchainAccountIsm": "0x99fEFc1119E86Ee0153eb887cF8E8ab2d92A16e8", "interchainAccountRouter": "0xbB88a31E4b709b645c06825c0E0b5CAC906d97DE", "interchainGasPaymaster": "0xe8d5590F2e969F9d21f0132f2b596273f8a03Ef2", - "interchainSecurityModule": "0xe274f228f87c0D72241CF9aAC15d91e3630aE6f6", + "interchainSecurityModule": "0x58D6fb4aADd3ae83ec529d3d0f42Ae904207a336", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0xDab56C5A1EffFdd23f6BD1243E457B1575984Bc6", "pausableHook": "0x73db9c7430548f399e335f3424e8d56080e9010c", @@ -4485,7 +4494,7 @@ "interchainAccountIsm": "0xFB9e40D811Cea562cc8a322b029eF2BDcC3ef6ed", "interchainAccountRouter": "0xeE8C0E1EeBfFCC451a013336386eA53E42a44451", "interchainGasPaymaster": "0x148CF67B8A242c1360bb2C93fCe203EC4d4f9B56", - "interchainSecurityModule": "0x01031eCa87184c84938016E1444150472Da35b3a", + "interchainSecurityModule": "0x81EC949b07e033b0346E60C2098464d115F0a997", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x53e912b41125d6094590a7DBEf1360d3d56EEa19", "pausableHook": "0x2d5918c3602F17937Ff982F7Bb7110774D3A24AD", @@ -4556,7 +4565,7 @@ "interchainAccountIsm": "0x9eb56085DdbDA60aDf7d2B533AFeD90e38fC9666", "interchainAccountRouter": "0x83475ca5bEB2Eaa59A2FF48a0544ebaa4a32c2de", "interchainGasPaymaster": "0x9024A3902B542C87a5C4A2b3e15d60B2f087Dc3E", - "interchainSecurityModule": "0x8750ac24C3bE28b406fBCD664AbabF676d3aCB29", + "interchainSecurityModule": "0x9dccF81bB9f419425b0a6584E8800556B92209Cc", "mailbox": "0x3a867fCfFeC2B790970eeBDC9023E75B0a172aa7", "merkleTreeHook": "0x9c44E6b8F0dB517C2c3a0478caaC5349b614F912", "pausableHook": "0x53e912b41125d6094590a7DBEf1360d3d56EEa19", @@ -4617,7 +4626,7 @@ "interchainAccountIsm": "0x61374178e45F65fF9D6252d017Cd580FC60B7654", "interchainAccountRouter": "0x783EC5e105234a570eB90f314284E5dBe53bdd90", "interchainGasPaymaster": "0xE56Da9D48E698eB70F56aeCC0BC25Ff1710EEA76", - "interchainSecurityModule": "0xE89fF24e1979F6AbD6b71b733cc62d1289d193c4", + "interchainSecurityModule": "0x9d1481A1fc2515aeE0Bf4eEeDDB75893DfAF0752", "mailbox": "0x3a464f746D23Ab22155710f44dB16dcA53e0775E", "merkleTreeHook": "0x4757Bdd68Bba8a6d901cEC82E61E184fF2986918", "pausableHook": "0x9024A3902B542C87a5C4A2b3e15d60B2f087Dc3E", @@ -4681,7 +4690,7 @@ "interchainAccountIsm": "0xFB9e40D811Cea562cc8a322b029eF2BDcC3ef6ed", "interchainAccountRouter": "0xeE8C0E1EeBfFCC451a013336386eA53E42a44451", "interchainGasPaymaster": "0x168DFF0Ad2b180F3801883Fe5Ae56d7E7d91D5f4", - "interchainSecurityModule": "0xFF16628ff85F145Ce6d1712014D46DcFB52da75A", + "interchainSecurityModule": "0x8f93c32C19986B891beA2bF317686Aa2336b3854", "mailbox": "0x02d16BC51af6BfD153d67CA61754cF912E82C4d9", "merkleTreeHook": "0x148CF67B8A242c1360bb2C93fCe203EC4d4f9B56", "pausableHook": "0xb129828B9EDa48192D0B2db35D0E40dCF51B3594", @@ -4746,7 +4755,7 @@ "interchainAccountIsm": "0xb5668713E9BA8bC96f97D691663E70b54CE90b0A", "interchainAccountRouter": "0xc5068BB6803ADbe5600DE5189fe27A4dAcE31170", "interchainGasPaymaster": "0xA1Df6B70044029a2D1eDDC50EfDE2813e478140a", - "interchainSecurityModule": "0x729E790E70902429873c23BaA73eE39aCEEfc461", + "interchainSecurityModule": "0x01180E7B92A4fEA1e250C92E32A02Df1cA058Fe0", "mailbox": "0x783EC5e105234a570eB90f314284E5dBe53bdd90", "merkleTreeHook": "0x25d668D37f20E6f396cB5DF1DFf5A3f2F568e707", "pausableHook": "0xC9ab9Dc82F05eA118F266611f4c474529d43b599", @@ -4771,6 +4780,69 @@ "transactionOverrides": { "gasPrice": 100000000 } + }, + "stride": { + "bech32Prefix": "stride", + "blockExplorers": [ + { + "apiUrl": "https://www.mintscan.io/stride", + "family": "other", + "name": "Mintscan", + "url": "https://www.mintscan.io/stride" + } + ], + "blocks": { + "confirmations": 1, + "estimateBlockTime": 5, + "reorgPeriod": 1 + }, + "chainId": "stride-1", + "deployer": { + "name": "Stride Labs", + "url": "https://www.stride.zone" + }, + "displayName": "Stride", + "domainId": 745, + "gasCurrencyCoinGeckoId": "stride", + "grpcUrls": [ + { + "http": "https://stride-grpc.publicnode.com:443" + } + ], + "isTestnet": false, + "name": "stride", + "nativeToken": { + "decimals": 6, + "denom": "ustrd", + "name": "Stride", + "symbol": "STRD" + }, + "protocol": "cosmos", + "restUrls": [ + { + "http": "https://stride-api.polkachu.com" + } + ], + "rpcUrls": [ + { + "http": "https://stride-rpc.polkachu.com" + } + ], + "slip44": 118, + "interchainGasPaymaster": "0x0000000000000000000000000000000000000000000000000000000000000000", + "mailbox": "0x89945750e089d84581f194e1947a58480b335f18386ad4f761f05feebf5e2454", + "merkleTreeHook": "0x7ab4a8c3ba5371e34cd8d5dc584e0d924504fc21c3cbf41c3f64d436176bf007", + "validatorAnnounce": "0xf57d954bf3ddb5f1032a0e020a99e931215cf83ceb4de987c781488065aaae0d", + "gasPrice": { + "denom": "ustrd", + "amount": "0.005" + }, + "canonicalAsset": "ustrd", + "contractAddressBytes": 32, + "index": { + "from": 9152000, + "chunk": 5 + } } }, "defaultRpcConsensusType": "fallback" diff --git a/rust/main/hyperlane-base/src/contract_sync/mod.rs b/rust/main/hyperlane-base/src/contract_sync/mod.rs index 5105a1ade..8e6f8278f 100644 --- a/rust/main/hyperlane-base/src/contract_sync/mod.rs +++ b/rust/main/hyperlane-base/src/contract_sync/mod.rs @@ -170,7 +170,7 @@ where Ok(logs) => logs, Err(err) => { warn!(?err, ?range, "Error fetching logs in range"); - break SLEEP_DURATION; + break Some(SLEEP_DURATION); } }; @@ -196,13 +196,20 @@ where // Update cursor if let Err(err) = cursor.update(logs, range).await { warn!(?err, "Error updating cursor"); - break SLEEP_DURATION; + break Some(SLEEP_DURATION); }; - break Default::default(); + break None; }, - CursorAction::Sleep(duration) => duration, + CursorAction::Sleep(duration) => Some(duration), }; - sleep(sleep_duration).await + if let Some(sleep_duration) = sleep_duration { + debug!( + cursor = ?cursor, + ?sleep_duration, + "Cursor can't make progress, sleeping", + ); + sleep(sleep_duration).await + } } async fn dedupe_and_store_logs( diff --git a/rust/main/hyperlane-base/src/settings/chains.rs b/rust/main/hyperlane-base/src/settings/chains.rs index 8dcb2b9c5..0e08b2d15 100644 --- a/rust/main/hyperlane-base/src/settings/chains.rs +++ b/rust/main/hyperlane-base/src/settings/chains.rs @@ -10,13 +10,13 @@ use hyperlane_core::{ config::OperationBatchConfig, AggregationIsm, CcipReadIsm, ContractLocator, HyperlaneAbi, HyperlaneDomain, HyperlaneDomainProtocol, HyperlaneMessage, HyperlaneProvider, IndexMode, InterchainGasPaymaster, InterchainGasPayment, InterchainSecurityModule, Mailbox, - MerkleTreeHook, MerkleTreeInsertion, MultisigIsm, RoutingIsm, SequenceAwareIndexer, - ValidatorAnnounce, H256, + MerkleTreeHook, MerkleTreeInsertion, MultisigIsm, ReorgPeriod, RoutingIsm, + SequenceAwareIndexer, ValidatorAnnounce, H256, }; use hyperlane_cosmos as h_cosmos; use hyperlane_ethereum::{ self as h_eth, BuildableWithProvider, EthereumInterchainGasPaymasterAbi, EthereumMailboxAbi, - EthereumValidatorAnnounceAbi, + EthereumReorgPeriod, EthereumValidatorAnnounceAbi, }; use hyperlane_fuel as h_fuel; use hyperlane_sealevel as h_sealevel; @@ -45,7 +45,7 @@ pub struct ChainConf { /// Signer configuration for this chain pub signer: Option, /// The reorg period of the chain, i.e. the number of blocks until finality - pub reorg_period: u32, + pub reorg_period: ReorgPeriod, /// Addresses of contracts on the chain pub addresses: CoreContractAddresses, /// The chain connection details @@ -272,13 +272,13 @@ impl ChainConf { match &self.connection { ChainConnectionConf::Ethereum(conf) => { + let reorg_period = + EthereumReorgPeriod::try_from(&self.reorg_period).context(ctx)?; self.build_ethereum( conf, &locator, metrics, - h_eth::SequenceIndexerBuilder { - reorg_period: self.reorg_period, - }, + h_eth::SequenceIndexerBuilder { reorg_period }, ) .await } @@ -289,11 +289,12 @@ impl ChainConf { } ChainConnectionConf::Cosmos(conf) => { let signer = self.cosmos_signer().await.context(ctx)?; + let reorg_period = self.reorg_period.as_blocks().context(ctx)?; let indexer = Box::new(h_cosmos::CosmosMailboxDispatchIndexer::new( conf.clone(), locator, signer, - self.reorg_period, + reorg_period, )?); Ok(indexer as Box>) } @@ -311,13 +312,13 @@ impl ChainConf { match &self.connection { ChainConnectionConf::Ethereum(conf) => { + let reorg_period = + EthereumReorgPeriod::try_from(&self.reorg_period).context(ctx)?; self.build_ethereum( conf, &locator, metrics, - h_eth::DeliveryIndexerBuilder { - reorg_period: self.reorg_period, - }, + h_eth::DeliveryIndexerBuilder { reorg_period }, ) .await } @@ -328,11 +329,12 @@ impl ChainConf { } ChainConnectionConf::Cosmos(conf) => { let signer = self.cosmos_signer().await.context(ctx)?; + let reorg_period = self.reorg_period.as_blocks().context(ctx)?; let indexer = Box::new(h_cosmos::CosmosMailboxDeliveryIndexer::new( conf.clone(), locator, signer, - self.reorg_period, + reorg_period, )?); Ok(indexer as Box>) } @@ -389,13 +391,15 @@ impl ChainConf { match &self.connection { ChainConnectionConf::Ethereum(conf) => { + let reorg_period = + EthereumReorgPeriod::try_from(&self.reorg_period).context(ctx)?; self.build_ethereum( conf, &locator, metrics, h_eth::InterchainGasPaymasterIndexerBuilder { mailbox_address: self.addresses.mailbox.into(), - reorg_period: self.reorg_period, + reorg_period, }, ) .await @@ -408,10 +412,11 @@ impl ChainConf { Ok(indexer as Box>) } ChainConnectionConf::Cosmos(conf) => { + let reorg_period = self.reorg_period.as_blocks().context(ctx)?; let indexer = Box::new(h_cosmos::CosmosInterchainGasPaymasterIndexer::new( conf.clone(), locator, - self.reorg_period, + reorg_period, )?); Ok(indexer as Box>) } @@ -429,13 +434,13 @@ impl ChainConf { match &self.connection { ChainConnectionConf::Ethereum(conf) => { + let reorg_period = + EthereumReorgPeriod::try_from(&self.reorg_period).context(ctx)?; self.build_ethereum( conf, &locator, metrics, - h_eth::MerkleTreeHookIndexerBuilder { - reorg_period: self.reorg_period, - }, + h_eth::MerkleTreeHookIndexerBuilder { reorg_period }, ) .await } @@ -450,12 +455,13 @@ impl ChainConf { } ChainConnectionConf::Cosmos(conf) => { let signer = self.cosmos_signer().await.context(ctx)?; + let reorg_period = self.reorg_period.as_blocks().context(ctx)?; let indexer = Box::new(h_cosmos::CosmosMerkleTreeHookIndexer::new( conf.clone(), locator, // TODO: remove signer requirement entirely signer, - self.reorg_period, + reorg_period, )?); Ok(indexer as Box>) } diff --git a/rust/main/hyperlane-base/src/settings/checkpoint_syncer.rs b/rust/main/hyperlane-base/src/settings/checkpoint_syncer.rs index 38274dafa..3434a7168 100644 --- a/rust/main/hyperlane-base/src/settings/checkpoint_syncer.rs +++ b/rust/main/hyperlane-base/src/settings/checkpoint_syncer.rs @@ -180,7 +180,7 @@ mod test { use std::panic::AssertUnwindSafe; use futures_util::FutureExt; - use hyperlane_core::{ReorgEvent, H256}; + use hyperlane_core::{ReorgEvent, ReorgPeriod, H256}; #[tokio::test] async fn test_build_and_validate() { @@ -209,7 +209,7 @@ mod test { .unwrap(); let dummy_checkpoint_index = 56; let unix_timestamp = 1620000000; - let reorg_period = 5; + let reorg_period = ReorgPeriod::from_blocks(5); let dummy_reorg_event = ReorgEvent { local_merkle_root: dummy_local_merkle_root, canonical_merkle_root: dummy_canonical_merkle_root, @@ -237,7 +237,9 @@ mod test { canonical_merkle_root: 0xb437b888332ef12f7260c7f679aad3c96b91ab81c2dc7242f8b290f0b6bba92b, checkpoint_index: 56, unix_timestamp: 1620000000, - reorg_period: 5, + reorg_period: Blocks( + 5, + ), }. Please resolve the reorg to continue."# ); } else { diff --git a/rust/main/hyperlane-base/src/settings/parser/mod.rs b/rust/main/hyperlane-base/src/settings/parser/mod.rs index 65a8c845a..d176ad857 100644 --- a/rust/main/hyperlane-base/src/settings/parser/mod.rs +++ b/rust/main/hyperlane-base/src/settings/parser/mod.rs @@ -19,7 +19,7 @@ use url::Url; use h_cosmos::RawCosmosAmount; use hyperlane_core::{ cfg_unwrap_all, config::*, HyperlaneDomain, HyperlaneDomainProtocol, - HyperlaneDomainTechnicalStack, IndexMode, + HyperlaneDomainTechnicalStack, IndexMode, ReorgPeriod, }; use crate::settings::{ @@ -34,6 +34,8 @@ pub use self::json_value_parser::ValueParser; mod connection_parser; mod json_value_parser; +const DEFAULT_CHUNK_SIZE: u32 = 1999; + /// The base agent config #[derive(Debug, Deserialize)] #[serde(transparent)] @@ -136,8 +138,8 @@ fn parse_chain( .chain(&mut err) .get_opt_key("blocks") .get_key("reorgPeriod") - .parse_u32() - .unwrap_or(1); + .parse_value("Invalid reorgPeriod") + .unwrap_or(ReorgPeriod::from_blocks(1)); let rpcs = parse_base_and_override_urls(&chain, "rpcUrls", "customRpcUrls", "http", &mut err); @@ -152,7 +154,7 @@ fn parse_chain( .get_opt_key("index") .get_opt_key("chunk") .parse_u32() - .unwrap_or(1999); + .unwrap_or(DEFAULT_CHUNK_SIZE); let mode = chain .chain(&mut err) .get_opt_key("index") diff --git a/rust/main/hyperlane-core/src/chain.rs b/rust/main/hyperlane-core/src/chain.rs index bd73ff613..134881bf7 100644 --- a/rust/main/hyperlane-core/src/chain.rs +++ b/rust/main/hyperlane-core/src/chain.rs @@ -3,16 +3,20 @@ use std::{ fmt::{Debug, Formatter}, hash::{Hash, Hasher}, + num::NonZeroU32, }; use derive_new::new; use num_derive::FromPrimitive; use num_traits::FromPrimitive; -use serde::Serialize; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + #[cfg(feature = "strum")] use strum::{EnumIter, EnumString, IntoStaticStr}; -use crate::{utils::many_to_one, HyperlaneProtocolError, IndexMode, H160, H256}; +use crate::{ + utils::many_to_one, ChainCommunicationError, HyperlaneProtocolError, IndexMode, H160, H256, +}; #[derive(Debug, Clone)] pub struct Address(pub bytes::Bytes); @@ -39,6 +43,80 @@ impl<'a> std::fmt::Display for ContractLocator<'a> { } } +#[derive(Default, Debug, Clone, PartialEq)] +pub enum ReorgPeriod { + #[default] + None, + Blocks(NonZeroU32), + Tag(String), +} + +impl ReorgPeriod { + pub fn from_blocks(blocks: u32) -> Self { + NonZeroU32::try_from(blocks) + .map(ReorgPeriod::Blocks) + .unwrap_or(ReorgPeriod::None) + } + + pub fn as_blocks(&self) -> Result { + match self { + ReorgPeriod::None => Ok(0), + ReorgPeriod::Blocks(blocks) => Ok(blocks.get()), + ReorgPeriod::Tag(_) => Err(ChainCommunicationError::InvalidReorgPeriod(self.clone())), + } + } + + pub fn is_none(&self) -> bool { + matches!(self, ReorgPeriod::None) + } +} + +impl Serialize for ReorgPeriod { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + ReorgPeriod::None => serializer.serialize_u32(0), + ReorgPeriod::Blocks(blocks) => serializer.serialize_u32(blocks.get()), + ReorgPeriod::Tag(tag) => serializer.serialize_str(tag), + } + } +} + +impl<'de> Deserialize<'de> for ReorgPeriod { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de; + + struct ReorgPeriodVisitor; + + impl<'de> de::Visitor<'de> for ReorgPeriodVisitor { + type Value = ReorgPeriod; + + fn expecting(&self, f: &mut Formatter) -> std::fmt::Result { + f.write_str("reorgPeriod as a number or string") + } + + fn visit_u64(self, v: u64) -> Result { + let v = v.try_into().map_err(de::Error::custom)?; + Ok(ReorgPeriod::from_blocks(v)) + } + + fn visit_str(self, v: &str) -> Result { + match v.parse::() { + Ok(v) => self.visit_u32(v), + Err(_) => Ok(ReorgPeriod::Tag(v.to_string())), + } + } + } + + deserializer.deserialize_any(ReorgPeriodVisitor) + } +} + /// All domains supported by Hyperlane. #[derive(FromPrimitive, PartialEq, Eq, Debug, Clone, Copy, Hash, Serialize)] #[cfg_attr( @@ -221,6 +299,7 @@ pub enum HyperlaneDomainTechnicalStack { OpStack, PolygonCDK, PolkadotSubstrate, + ZkSync, #[default] Other, } @@ -304,6 +383,7 @@ impl KnownHyperlaneDomain { HyperlaneDomainTechnicalStack::PolkadotSubstrate: [ Moonbeam, Tangle ], + HyperlaneDomainTechnicalStack::ZkSync: [], HyperlaneDomainTechnicalStack::Other: [ Avalanche, BinanceSmartChain, Celo, EclipseMainnet, Endurance, Ethereum, FuseMainnet, Gnosis, Injective, Linea, Lukso, Neutron, Osmosis, Polygon, @@ -505,9 +585,9 @@ impl HyperlaneDomain { #[cfg(test)] #[cfg(feature = "strum")] mod tests { - use std::str::FromStr; + use std::{num::NonZeroU32, str::FromStr}; - use crate::KnownHyperlaneDomain; + use crate::{KnownHyperlaneDomain, ReorgPeriod}; #[test] fn domain_strings() { @@ -560,4 +640,32 @@ mod tests { ); assert!("foo".parse::().is_err()); } + + #[test] + fn parse_reorg_period() { + assert_eq!( + serde_json::from_value::(0.into()).unwrap(), + ReorgPeriod::None + ); + + assert_eq!( + serde_json::from_value::("0".into()).unwrap(), + ReorgPeriod::None + ); + + assert_eq!( + serde_json::from_value::(12.into()).unwrap(), + ReorgPeriod::Blocks(NonZeroU32::new(12).unwrap()) + ); + + assert_eq!( + serde_json::from_value::("12".into()).unwrap(), + ReorgPeriod::Blocks(NonZeroU32::new(12).unwrap()) + ); + + assert_eq!( + serde_json::from_value::("finalized".into()).unwrap(), + ReorgPeriod::Tag("finalized".into()) + ); + } } diff --git a/rust/main/hyperlane-core/src/error.rs b/rust/main/hyperlane-core/src/error.rs index 56bbf4a82..fe1385c0e 100644 --- a/rust/main/hyperlane-core/src/error.rs +++ b/rust/main/hyperlane-core/src/error.rs @@ -10,8 +10,10 @@ use crate::config::StrOrIntParseError; use crate::rpc_clients::RpcClientError; use std::string::FromUtf8Error; -use crate::HyperlaneProviderError; -use crate::{Error as PrimitiveTypeError, HyperlaneSignerError, H256, U256}; +use crate::{ + Error as PrimitiveTypeError, HyperlaneProviderError, HyperlaneSignerError, ReorgPeriod, H256, + U256, +}; /// The result of interacting with a chain. pub type ChainResult = Result; @@ -157,6 +159,9 @@ pub enum ChainCommunicationError { /// Hyperlane signer error #[error("{0}")] HyperlaneSignerError(#[from] HyperlaneSignerError), + /// Invalid reorg period + #[error("Invalid reorg period: {0:?}")] + InvalidReorgPeriod(ReorgPeriod), } impl ChainCommunicationError { diff --git a/rust/main/hyperlane-core/src/traits/mailbox.rs b/rust/main/hyperlane-core/src/traits/mailbox.rs index d5e9081b6..83646e659 100644 --- a/rust/main/hyperlane-core/src/traits/mailbox.rs +++ b/rust/main/hyperlane-core/src/traits/mailbox.rs @@ -1,12 +1,11 @@ use std::fmt::Debug; -use std::num::NonZeroU64; use async_trait::async_trait; use derive_new::new; use crate::{ traits::TxOutcome, utils::domain_hash, BatchItem, ChainCommunicationError, ChainResult, - HyperlaneContract, HyperlaneMessage, QueueOperation, TxCostEstimate, H256, U256, + HyperlaneContract, HyperlaneMessage, QueueOperation, ReorgPeriod, TxCostEstimate, H256, U256, }; /// Interface for the Mailbox chain contract. Allows abstraction over different @@ -20,9 +19,9 @@ pub trait Mailbox: HyperlaneContract + Send + Sync + Debug { /// Gets the current leaf count of the merkle tree /// - /// - `lag` is how far behind the current block to query, if not specified + /// - `reorg_period` is how far behind the current block to query, if not specified /// it will query at the latest block. - async fn count(&self, lag: Option) -> ChainResult; + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult; /// Fetch the status of a message async fn delivered(&self, id: H256) -> ChainResult; diff --git a/rust/main/hyperlane-core/src/traits/merkle_tree_hook.rs b/rust/main/hyperlane-core/src/traits/merkle_tree_hook.rs index 35f3fa4ef..183ca7383 100644 --- a/rust/main/hyperlane-core/src/traits/merkle_tree_hook.rs +++ b/rust/main/hyperlane-core/src/traits/merkle_tree_hook.rs @@ -1,11 +1,11 @@ use std::fmt::Debug; -use std::num::NonZeroU64; use async_trait::async_trait; use auto_impl::auto_impl; use crate::{ accumulator::incremental::IncrementalMerkle, ChainResult, Checkpoint, HyperlaneContract, + ReorgPeriod, }; /// Interface for the MerkleTreeHook chain contract. Allows abstraction over different @@ -15,19 +15,19 @@ use crate::{ pub trait MerkleTreeHook: HyperlaneContract + Send + Sync + Debug { /// Return the incremental merkle tree in storage /// - /// - `lag` is how far behind the current block to query, if not specified + /// - `reorg_period` is how far behind the current block to query, if not specified /// it will query at the latest block. - async fn tree(&self, lag: Option) -> ChainResult; + async fn tree(&self, reorg_period: &ReorgPeriod) -> ChainResult; /// Gets the current leaf count of the merkle tree /// - /// - `lag` is how far behind the current block to query, if not specified + /// - `reorg_period` is how far behind the current block to query, if not specified /// it will query at the latest block. - async fn count(&self, lag: Option) -> ChainResult; + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult; /// Get the latest checkpoint. /// - /// - `lag` is how far behind the current block to query, if not specified + /// - `reorg_period` is how far behind the current block to query, if not specified /// it will query at the latest block. - async fn latest_checkpoint(&self, lag: Option) -> ChainResult; + async fn latest_checkpoint(&self, reorg_period: &ReorgPeriod) -> ChainResult; } diff --git a/rust/main/hyperlane-core/src/types/reorg.rs b/rust/main/hyperlane-core/src/types/reorg.rs index 00a8dedc1..eb41844c0 100644 --- a/rust/main/hyperlane-core/src/types/reorg.rs +++ b/rust/main/hyperlane-core/src/types/reorg.rs @@ -1,7 +1,7 @@ use derive_new::new; use serde::{Deserialize, Serialize}; -use crate::H256; +use crate::{ReorgPeriod, H256}; /// Details about a detected chain reorg, from an agent's perspective #[derive(Debug, Clone, Serialize, Deserialize, new)] @@ -15,6 +15,6 @@ pub struct ReorgEvent { pub checkpoint_index: u32, /// the timestamp when the reorg was detected, in seconds since the Unix epoch pub unix_timestamp: u64, - /// the reorg period configured for the agent, in blocks - pub reorg_period: u64, + /// the reorg period configured for the agent + pub reorg_period: ReorgPeriod, } diff --git a/rust/main/hyperlane-test/src/mocks/mailbox.rs b/rust/main/hyperlane-test/src/mocks/mailbox.rs index dc09e1026..7333e2c8a 100644 --- a/rust/main/hyperlane-test/src/mocks/mailbox.rs +++ b/rust/main/hyperlane-test/src/mocks/mailbox.rs @@ -1,7 +1,5 @@ #![allow(non_snake_case)] -use std::num::NonZeroU64; - use async_trait::async_trait; use mockall::*; @@ -28,11 +26,11 @@ mock! { nonce: usize, ) -> ChainResult> {} - pub fn _tree(&self, maybe_lag: Option) -> ChainResult {} + pub fn _tree(&self, reorg_period: &ReorgPeriod) -> ChainResult {} - pub fn _count(&self, maybe_lag: Option) -> ChainResult {} + pub fn _count(&self, reorg_period: &ReorgPeriod) -> ChainResult {} - pub fn _latest_checkpoint(&self, maybe_lag: Option) -> ChainResult {} + pub fn _latest_checkpoint(&self, reorg_period: &ReorgPeriod) -> ChainResult {} pub fn _default_ism(&self) -> ChainResult {} pub fn _recipient_ism(&self, recipient: H256) -> ChainResult {} @@ -68,8 +66,8 @@ impl std::fmt::Debug for MockMailboxContract { #[async_trait] impl Mailbox for MockMailboxContract { - async fn count(&self, maybe_lag: Option) -> ChainResult { - self._count(maybe_lag) + async fn count(&self, reorg_period: &ReorgPeriod) -> ChainResult { + self._count(reorg_period) } async fn default_ism(&self) -> ChainResult { diff --git a/solidity/CHANGELOG.md b/solidity/CHANGELOG.md index 01d7e99ae..dbffd611f 100644 --- a/solidity/CHANGELOG.md +++ b/solidity/CHANGELOG.md @@ -1,5 +1,19 @@ # @hyperlane-xyz/core +## 5.5.0 + +### Minor Changes + +- 72c23c0d6: Added PRECISION and rateUpdateNonce to ensure compatibility of HypERC4626 + +### Patch Changes + +- c9085afd9: Patched OPL2ToL1Ism to check for correct messageId for external call in verify +- ec6b874b1: Added nonce to HypERC4626 +- Updated dependencies [f1712deb7] +- Updated dependencies [29341950e] + - @hyperlane-xyz/utils@5.6.0 + ## 5.4.1 ### Patch Changes diff --git a/solidity/contracts/PackageVersioned.sol b/solidity/contracts/PackageVersioned.sol index f0d43b725..eb57706c1 100644 --- a/solidity/contracts/PackageVersioned.sol +++ b/solidity/contracts/PackageVersioned.sol @@ -7,5 +7,5 @@ pragma solidity >=0.6.11; **/ abstract contract PackageVersioned { // GENERATED CODE - DO NOT EDIT - string public constant PACKAGE_VERSION = "5.4.1"; + string public constant PACKAGE_VERSION = "5.5.0"; } diff --git a/solidity/contracts/client/GasRouter.sol b/solidity/contracts/client/GasRouter.sol index c5f9efd1c..f14d0b642 100644 --- a/solidity/contracts/client/GasRouter.sol +++ b/solidity/contracts/client/GasRouter.sol @@ -1,10 +1,25 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.6.11; +/*@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@ HYPERLANE @@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ +@@@@@@@@@ @@@@@@@@*/ + +// ============ Internal Imports ============ import {Router} from "./Router.sol"; import {StandardHookMetadata} from "../hooks/libs/StandardHookMetadata.sol"; abstract contract GasRouter is Router { + event GasSet(uint32 domain, uint256 gas); + // ============ Mutable Storage ============ mapping(uint32 => uint256) public destinationGas; @@ -56,6 +71,7 @@ abstract contract GasRouter is Router { function _setDestinationGas(uint32 domain, uint256 gas) internal { destinationGas[domain] = gas; + emit GasSet(domain, gas); } function _GasRouter_dispatch( diff --git a/solidity/contracts/libs/TypeCasts.sol b/solidity/contracts/libs/TypeCasts.sol index 4440f63da..d156e9850 100644 --- a/solidity/contracts/libs/TypeCasts.sol +++ b/solidity/contracts/libs/TypeCasts.sol @@ -9,6 +9,10 @@ library TypeCasts { // alignment preserving cast function bytes32ToAddress(bytes32 _buf) internal pure returns (address) { + require( + uint256(_buf) <= uint256(type(uint160).max), + "TypeCasts: bytes32ToAddress overflow" + ); return address(uint160(uint256(_buf))); } } diff --git a/solidity/contracts/token/HypERC20Collateral.sol b/solidity/contracts/token/HypERC20Collateral.sol index 858a3140b..69b137e75 100644 --- a/solidity/contracts/token/HypERC20Collateral.sol +++ b/solidity/contracts/token/HypERC20Collateral.sol @@ -1,10 +1,25 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.8.0; +/*@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@ HYPERLANE @@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ +@@@@@@@@@ @@@@@@@@*/ + +// ============ Internal Imports ============ import {TokenRouter} from "./libs/TokenRouter.sol"; import {TokenMessage} from "./libs/TokenMessage.sol"; import {MailboxClient} from "../client/MailboxClient.sol"; +// ============ External Imports ============ +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -22,6 +37,7 @@ contract HypERC20Collateral is TokenRouter { * @param erc20 Address of the token to keep as collateral */ constructor(address erc20, address _mailbox) TokenRouter(_mailbox) { + require(Address.isContract(erc20), "HypERC20Collateral: invalid token"); wrappedToken = IERC20(erc20); } diff --git a/solidity/contracts/token/extensions/HypERC4626Collateral.sol b/solidity/contracts/token/extensions/HypERC4626Collateral.sol index 87528b109..1f164563e 100644 --- a/solidity/contracts/token/extensions/HypERC4626Collateral.sol +++ b/solidity/contracts/token/extensions/HypERC4626Collateral.sol @@ -66,11 +66,7 @@ contract HypERC4626Collateral is HypERC20Collateral { // Can't override _transferFromSender only because we need to pass shares in the token message _transferFromSender(_amount); uint256 _shares = _depositIntoVault(_amount); - uint256 _exchangeRate = PRECISION.mulDiv( - vault.totalAssets(), - vault.totalSupply(), - Math.Rounding.Down - ); + uint256 _exchangeRate = vault.convertToAssets(PRECISION); rateUpdateNonce++; bytes memory _tokenMetadata = abi.encode( @@ -121,15 +117,19 @@ contract HypERC4626Collateral is HypERC20Collateral { * @dev Update the exchange rate on the synthetic token by accounting for additional yield accrued to the underlying vault * @param _destinationDomain domain of the vault */ - function rebase(uint32 _destinationDomain) public payable { + function rebase( + uint32 _destinationDomain, + bytes calldata _hookMetadata, + address _hook + ) public payable { // force a rebase with an empty transfer to 0x1 _transferRemote( _destinationDomain, NULL_RECIPIENT, 0, msg.value, - bytes(""), - address(0) + _hookMetadata, + _hook ); } } diff --git a/solidity/contracts/token/extensions/WHypERC4626.sol b/solidity/contracts/token/extensions/WHypERC4626.sol new file mode 100644 index 000000000..08cb59732 --- /dev/null +++ b/solidity/contracts/token/extensions/WHypERC4626.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity >=0.8.0; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {HypERC4626} from "./HypERC4626.sol"; +import {PackageVersioned} from "../../PackageVersioned.sol"; + +/*@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@ HYPERLANE @@@@@@@ + @@@@@@@@@@@@@@@@@@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ + @@@@@@@@@ @@@@@@@@@ +@@@@@@@@@ @@@@@@@@*/ + +/** + * @title WHypERC4626 + * @author Abacus Works + * @notice A wrapper for HypERC4626 that allows for wrapping and unwrapping of underlying rebasing tokens + */ +contract WHypERC4626 is ERC20, PackageVersioned { + HypERC4626 public immutable underlying; + + constructor( + HypERC4626 _underlying, + string memory name, + string memory symbol + ) ERC20(name, symbol) { + underlying = _underlying; + } + + /* + * @notice Wraps an amount of underlying tokens into wrapped tokens + * @param _underlyingAmount The amount of underlying tokens to wrap + * @return The amount of wrapped tokens + */ + function wrap(uint256 _underlyingAmount) external returns (uint256) { + require( + _underlyingAmount > 0, + "WHypERC4626: wrap amount must be greater than 0" + ); + uint256 wrappedAmount = underlying.assetsToShares(_underlyingAmount); + _mint(msg.sender, wrappedAmount); + underlying.transferFrom(msg.sender, address(this), _underlyingAmount); + return wrappedAmount; + } + + /* + * @notice Unwraps an amount of wrapped tokens into underlying tokens + * @param _wrappedAmount The amount of wrapped tokens to unwrap + * @return The amount of underlying tokens + */ + function unwrap(uint256 _wrappedAmount) external returns (uint256) { + require( + _wrappedAmount > 0, + "WHypERC4626: unwrap amount must be greater than 0" + ); + uint256 underlyingAmount = underlying.sharesToAssets(_wrappedAmount); + _burn(msg.sender, _wrappedAmount); + underlying.transfer(msg.sender, underlyingAmount); + return underlyingAmount; + } + + /* + * @notice Gets the amount of wrapped tokens for a given amount of underlying tokens + * @param _underlyingAmount The amount of underlying tokens + * @return The amount of wrapped tokens + */ + function getWrappedAmount( + uint256 _underlyingAmount + ) external view returns (uint256) { + return underlying.assetsToShares(_underlyingAmount); + } + + /* + * @notice Gets the amount of underlying tokens for a given amount of wrapped tokens + * @param _wrappedAmount The amount of wrapped tokens + * @return The amount of underlying tokens + */ + function getUnderlyingAmount( + uint256 _wrappedAmount + ) external view returns (uint256) { + return underlying.sharesToAssets(_wrappedAmount); + } + + /* + * @notice Gets the amount of wrapped tokens for 1 unit of underlying tokens + * @return The amount of wrapped tokens + */ + function wrappedPerUnderlying() external view returns (uint256) { + return underlying.assetsToShares(1 * 10 ** underlying.decimals()); + } + + /* + * @notice Gets the amount of underlying tokens for 1 unit of wrapped tokens + * @return The amount of underlying tokens + */ + function underlyingPerWrapped() external view returns (uint256) { + return underlying.sharesToAssets(1 * 10 ** decimals()); + } + + /* + * @notice Gets the decimals of the wrapped token + * @return The decimals of the wrapped token + */ + function decimals() public view override returns (uint8) { + return underlying.decimals(); + } +} diff --git a/solidity/package.json b/solidity/package.json index 7fb78e878..78c42ca78 100644 --- a/solidity/package.json +++ b/solidity/package.json @@ -1,11 +1,11 @@ { "name": "@hyperlane-xyz/core", "description": "Core solidity contracts for Hyperlane", - "version": "5.4.1", + "version": "5.5.0", "dependencies": { "@arbitrum/nitro-contracts": "^1.2.1", "@eth-optimism/contracts": "^0.6.0", - "@hyperlane-xyz/utils": "5.5.0", + "@hyperlane-xyz/utils": "5.6.0", "@layerzerolabs/lz-evm-oapp-v2": "2.0.2", "@openzeppelin/contracts": "^4.9.3", "@openzeppelin/contracts-upgradeable": "^v4.9.3", diff --git a/solidity/test/GasRouter.t.sol b/solidity/test/GasRouter.t.sol index aaf73b2a3..becd43cf3 100644 --- a/solidity/test/GasRouter.t.sol +++ b/solidity/test/GasRouter.t.sol @@ -68,6 +68,8 @@ contract GasRouterTest is Test { } function testSetDestinationGas(uint256 gas) public { + vm.expectEmit(true, true, true, true); + emit GasRouter.GasSet(originDomain, gas); setDestinationGas(remoteRouter, originDomain, gas); assertEq(remoteRouter.destinationGas(originDomain), gas); diff --git a/solidity/test/isms/RateLimitedIsm.t.sol b/solidity/test/isms/RateLimitedIsm.t.sol index 7c4b76356..481bbaa49 100644 --- a/solidity/test/isms/RateLimitedIsm.t.sol +++ b/solidity/test/isms/RateLimitedIsm.t.sol @@ -75,7 +75,7 @@ contract RateLimitedIsmTest is Test { TokenMessage.format(bytes32(""), _amount, bytes("")) ); - vm.expectRevert("InvalidRecipient"); + vm.expectRevert("TypeCasts: bytes32ToAddress overflow"); rateLimitedIsm.verify(bytes(""), _message); } diff --git a/solidity/test/token/HypERC20.t.sol b/solidity/test/token/HypERC20.t.sol index 9c068b239..c3b7da74c 100644 --- a/solidity/test/token/HypERC20.t.sol +++ b/solidity/test/token/HypERC20.t.sol @@ -406,6 +406,11 @@ contract HypERC20CollateralTest is HypTokenTest { _enrollRemoteTokenRouter(); } + function test_constructor_revert_ifInvalidToken() public { + vm.expectRevert("HypERC20Collateral: invalid token"); + new HypERC20Collateral(address(0), address(localMailbox)); + } + function testInitialize_revert_ifAlreadyInitialized() public {} function testRemoteTransfer() public { diff --git a/solidity/test/token/HypERC4626Test.t.sol b/solidity/test/token/HypERC4626Test.t.sol index 338d39b75..ef9243148 100644 --- a/solidity/test/token/HypERC4626Test.t.sol +++ b/solidity/test/token/HypERC4626Test.t.sol @@ -24,7 +24,9 @@ import {MockMailbox} from "../../contracts/mock/MockMailbox.sol"; import {HypERC20} from "../../contracts/token/HypERC20.sol"; import {HypERC4626Collateral} from "../../contracts/token/extensions/HypERC4626Collateral.sol"; import {HypERC4626} from "../../contracts/token/extensions/HypERC4626.sol"; +import {StandardHookMetadata} from "../../contracts/hooks/libs/StandardHookMetadata.sol"; import "../../contracts/test/ERC4626/ERC4626Test.sol"; +import {ProtocolFee} from "../../contracts/hooks/ProtocolFee.sol"; contract HypERC4626CollateralTest is HypTokenTest { using TypeCasts for address; @@ -124,14 +126,38 @@ contract HypERC4626CollateralTest is HypTokenTest { _accrueYield(); - localRebasingToken.rebase(DESTINATION); + localRebasingToken.rebase(DESTINATION, bytes(""), address(0)); remoteMailbox.processNextInboundMessage(); - assertEq( + assertApproxEqRelDecimal( remoteToken.balanceOf(BOB), - transferAmount + _discountedYield() + transferAmount + _discountedYield(), + 1e14, + 0 ); } + function testRemoteTransfer_rebaseWithCustomHook() public { + _performRemoteTransferWithoutExpectation(0, transferAmount); + assertEq(remoteToken.balanceOf(BOB), transferAmount); + + _accrueYield(); + + uint256 FEE = 1e18; + ProtocolFee customHook = new ProtocolFee( + FEE, + FEE, + address(this), + address(this) + ); + + localRebasingToken.rebase{value: FEE}( + DESTINATION, + StandardHookMetadata.overrideMsgValue(FEE), + address(customHook) + ); + assertEq(address(customHook).balance, FEE); + } + function testRebaseWithTransfer() public { _performRemoteTransferWithoutExpectation(0, transferAmount); assertEq(remoteToken.balanceOf(BOB), transferAmount); @@ -275,7 +301,7 @@ contract HypERC4626CollateralTest is HypTokenTest { _accrueYield(); - localRebasingToken.rebase(DESTINATION); + localRebasingToken.rebase(DESTINATION, bytes(""), address(0)); remoteMailbox.processNextInboundMessage(); // Use balance here since it might be off by <1bp @@ -314,7 +340,7 @@ contract HypERC4626CollateralTest is HypTokenTest { _accrueYield(); _accrueYield(); // earning 2x yield to be split - localRebasingToken.rebase(DESTINATION); + localRebasingToken.rebase(DESTINATION, bytes(""), address(0)); vm.prank(CAROL); remoteToken.transferRemote( @@ -352,7 +378,7 @@ contract HypERC4626CollateralTest is HypTokenTest { // decrease collateral in vault by 10% uint256 drawdown = 5e18; primaryToken.burnFrom(address(vault), drawdown); - localRebasingToken.rebase(DESTINATION); + localRebasingToken.rebase(DESTINATION, bytes(""), address(0)); remoteMailbox.processNextInboundMessage(); // Use balance here since it might be off by <1bp @@ -378,7 +404,7 @@ contract HypERC4626CollateralTest is HypTokenTest { _accrueYield(); - localRebasingToken.rebase(DESTINATION); + localRebasingToken.rebase(DESTINATION, bytes(""), address(0)); remoteMailbox.processNextInboundMessage(); vm.prank(BOB); @@ -389,13 +415,23 @@ contract HypERC4626CollateralTest is HypTokenTest { ); peerMailbox.processNextInboundMessage(); - assertEq(remoteRebasingToken.exchangeRate(), 1045e7); // 5 * 0.9 = 4.5% yield + assertApproxEqRelDecimal( + remoteRebasingToken.exchangeRate(), + 1045e7, + 1e14, + 0 + ); // 5 * 0.9 = 4.5% yield assertEq(peerRebasingToken.exchangeRate(), 1e10); // assertingthat transfers by the synthetic variant don't impact the exchang rate - localRebasingToken.rebase(PEER_DESTINATION); + localRebasingToken.rebase(PEER_DESTINATION, bytes(""), address(0)); peerMailbox.processNextInboundMessage(); - assertEq(peerRebasingToken.exchangeRate(), 1045e7); // asserting that the exchange rate is set finally by the collateral variant + assertApproxEqRelDecimal( + peerRebasingToken.exchangeRate(), + 1045e7, + 1e14, + 0 + ); // asserting that the exchange rate is set finally by the collateral variant } function test_cyclicTransfers() public { @@ -405,7 +441,7 @@ contract HypERC4626CollateralTest is HypTokenTest { _accrueYield(); - localRebasingToken.rebase(DESTINATION); // yield is added + localRebasingToken.rebase(DESTINATION, bytes(""), address(0)); // yield is added remoteMailbox.processNextInboundMessage(); // BOB: remote -> peer(BOB) (yield is leftover) @@ -417,7 +453,7 @@ contract HypERC4626CollateralTest is HypTokenTest { ); peerMailbox.processNextInboundMessage(); - localRebasingToken.rebase(PEER_DESTINATION); + localRebasingToken.rebase(PEER_DESTINATION, bytes(""), address(0)); peerMailbox.processNextInboundMessage(); // BOB: peer -> local(CAROL) @@ -457,11 +493,13 @@ contract HypERC4626CollateralTest is HypTokenTest { _accrueYield(); - localRebasingToken.rebase(DESTINATION); + localRebasingToken.rebase(DESTINATION, bytes(""), address(0)); remoteMailbox.processNextInboundMessage(); - assertEq( + assertApproxEqRelDecimal( remoteToken.balanceOf(BOB), - transferAmount + _discountedYield() + transferAmount + _discountedYield(), + 1e14, + 0 ); vm.prank(address(localMailbox)); diff --git a/solidity/test/token/WHypERC4626.t.sol b/solidity/test/token/WHypERC4626.t.sol new file mode 100644 index 000000000..5684eeee2 --- /dev/null +++ b/solidity/test/token/WHypERC4626.t.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8.13; + +import {Test} from "forge-std/Test.sol"; +import {MockMailbox} from "../../contracts/mock/MockMailbox.sol"; +import {WHypERC4626} from "../../contracts/token/extensions/WHypERC4626.sol"; +import {HypERC4626} from "../../contracts/token/extensions/HypERC4626.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract MockHypERC4626 is HypERC4626 { + constructor(address _mailbox) HypERC4626(18, _mailbox, 2) {} + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} + +contract WHypERC4626Test is Test { + WHypERC4626 public wHypERC4626; + MockHypERC4626 public underlyingToken; + address public alice = address(0x1); + address public bob = address(0x2); + + function setUp() public { + MockMailbox mailbox = new MockMailbox(1); + underlyingToken = new MockHypERC4626(address(mailbox)); + wHypERC4626 = new WHypERC4626( + underlyingToken, + "Wrapped Rebasing Token", + "WRT" + ); + + underlyingToken.mint(alice, 1000 * 10 ** 18); + underlyingToken.mint(bob, 1000 * 10 ** 18); + } + + function test_wrap() public { + uint256 amount = 100 * 10 ** 18; + + vm.startPrank(alice); + underlyingToken.approve(address(wHypERC4626), amount); + uint256 wrappedAmount = wHypERC4626.wrap(amount); + + assertEq(wHypERC4626.balanceOf(alice), wrappedAmount); + assertEq(underlyingToken.balanceOf(alice), 900 * 10 ** 18); + vm.stopPrank(); + } + + function test_wrap_revertsWhen_zeroAmount() public { + vm.startPrank(alice); + underlyingToken.approve(address(wHypERC4626), 0); + vm.expectRevert("WHypERC4626: wrap amount must be greater than 0"); + wHypERC4626.wrap(0); + vm.stopPrank(); + } + + function test_unwrap() public { + uint256 amount = 100 * 10 ** 18; + + vm.startPrank(alice); + underlyingToken.approve(address(wHypERC4626), amount); + uint256 wrappedAmount = wHypERC4626.wrap(amount); + + uint256 unwrappedAmount = wHypERC4626.unwrap(wrappedAmount); + + assertEq(wHypERC4626.balanceOf(alice), 0); + assertEq(underlyingToken.balanceOf(alice), 1000 * 10 ** 18); + assertEq(unwrappedAmount, amount); + vm.stopPrank(); + } + + function test_unwrap_revertsWhen_zeroAmount() public { + vm.startPrank(alice); + vm.expectRevert("WHypERC4626: unwrap amount must be greater than 0"); + wHypERC4626.unwrap(0); + vm.stopPrank(); + } + + function test_getWrappedAmount() public view { + uint256 amount = 100 * 10 ** 18; + uint256 wrappedAmount = wHypERC4626.getWrappedAmount(amount); + + assertEq(wrappedAmount, underlyingToken.assetsToShares(amount)); + } + + function test_getUnderlyingAmount() public view { + uint256 amount = 100 * 10 ** 18; + uint256 underlyingAmount = wHypERC4626.getUnderlyingAmount(amount); + + assertEq(underlyingAmount, underlyingToken.sharesToAssets(amount)); + } + + function test_wrappedPerUnderlying() public view { + uint256 wrappedPerUnderlying = wHypERC4626.wrappedPerUnderlying(); + + assertEq( + wrappedPerUnderlying, + underlyingToken.assetsToShares(1 * 10 ** underlyingToken.decimals()) + ); + } + + function test_underlyingPerWrapped() public view { + uint256 underlyingPerWrapped = wHypERC4626.underlyingPerWrapped(); + + assertEq( + underlyingPerWrapped, + underlyingToken.sharesToAssets(1 * 10 ** underlyingToken.decimals()) + ); + } + + function test_decimals() public view { + uint8 decimals = wHypERC4626.decimals(); + + assertEq(decimals, underlyingToken.decimals()); + } +} diff --git a/typescript/ccip-server/CHANGELOG.md b/typescript/ccip-server/CHANGELOG.md index 2f082f6b2..6ec43d13c 100644 --- a/typescript/ccip-server/CHANGELOG.md +++ b/typescript/ccip-server/CHANGELOG.md @@ -1,5 +1,7 @@ # @hyperlane-xyz/ccip-server +## 5.6.0 + ## 5.5.0 ## 5.4.0 diff --git a/typescript/ccip-server/package.json b/typescript/ccip-server/package.json index c58df422c..457654431 100644 --- a/typescript/ccip-server/package.json +++ b/typescript/ccip-server/package.json @@ -1,6 +1,6 @@ { "name": "@hyperlane-xyz/ccip-server", - "version": "5.5.0", + "version": "5.6.0", "description": "CCIP server", "typings": "dist/index.d.ts", "typedocMain": "src/index.ts", diff --git a/typescript/cli/.mocharc-e2e.json b/typescript/cli/.mocharc-e2e.json new file mode 100644 index 000000000..ecabac62f --- /dev/null +++ b/typescript/cli/.mocharc-e2e.json @@ -0,0 +1,8 @@ +{ + "extensions": ["ts"], + "spec": ["src/**/*.e2e-test.ts"], + "node-option": [ + "experimental-specifier-resolution=node", + "loader=ts-node/esm" + ] +} diff --git a/typescript/cli/.mocharc.json b/typescript/cli/.mocharc.json index 17ba33e2f..2d7433a2f 100644 --- a/typescript/cli/.mocharc.json +++ b/typescript/cli/.mocharc.json @@ -1,6 +1,6 @@ { "extensions": ["ts"], - "spec": ["src/**/*.test.*", "src/**/*.e2e-test.ts"], + "spec": ["src/**/*.test.*"], "node-option": [ "experimental-specifier-resolution=node", "loader=ts-node/esm" diff --git a/typescript/cli/CHANGELOG.md b/typescript/cli/CHANGELOG.md index 517b7ebe1..1cd6506a1 100644 --- a/typescript/cli/CHANGELOG.md +++ b/typescript/cli/CHANGELOG.md @@ -1,5 +1,38 @@ # @hyperlane-xyz/cli +## 5.6.0 + +### Minor Changes + +- 41035aac8: Add strategyUrl detect and validation in the beginning of `warp apply` + Remove yaml transactions print from `warp apply` +- 29341950e: Adds new `core check` command to compare local configuration and on chain deployments. Adds memoization to the EvmHookReader to avoid repeating configuration derivation +- 32d0a67c2: Adds the warp check command to compare warp routes config files with on chain warp route deployments +- 3662297fc: Add prompt in `warp init` command to choose if a trusted relayer should be used instead of making the choice by default for the user and enable the `--yes` flag to default to a trusted ISM +- b1ff48bd1: Add rebasing yield route support into CLI/SDK +- d41aa6928: Add `EthJsonRpcBlockParameterTag` enum for validating reorgPeriod +- c3e9268f1: Add support for an arbitrary string in `reorgPeriod`, which is used as a block tag to get the finalized block. +- a4d5d692f: Update `warp apply` such that it updates in place AND extends in a single call +- 01e7070eb: updates the multi chain selection prompt by adding search functionality and an optional confirmation prompt for the current selection + +### Patch Changes + +- e89f9e35d: Update registry to v4.7.0 +- Updated dependencies [f1712deb7] +- Updated dependencies [46044a2e9] +- Updated dependencies [02a5b92ba] +- Updated dependencies [29341950e] +- Updated dependencies [8001bbbd6] +- Updated dependencies [32d0a67c2] +- Updated dependencies [b1ff48bd1] +- Updated dependencies [d41aa6928] +- Updated dependencies [c3e9268f1] +- Updated dependencies [7d7bcc1a3] +- Updated dependencies [7f3e0669d] +- Updated dependencies [2317eca3c] + - @hyperlane-xyz/utils@5.6.0 + - @hyperlane-xyz/sdk@5.6.0 + ## 5.5.0 ### Patch Changes diff --git a/typescript/cli/package.json b/typescript/cli/package.json index ee91e5fc8..ab516e294 100644 --- a/typescript/cli/package.json +++ b/typescript/cli/package.json @@ -1,13 +1,13 @@ { "name": "@hyperlane-xyz/cli", - "version": "5.5.0", + "version": "5.6.0", "description": "A command-line utility for common Hyperlane operations", "dependencies": { "@aws-sdk/client-kms": "^3.577.0", "@aws-sdk/client-s3": "^3.577.0", "@hyperlane-xyz/registry": "4.7.0", - "@hyperlane-xyz/sdk": "5.5.0", - "@hyperlane-xyz/utils": "5.5.0", + "@hyperlane-xyz/sdk": "5.6.0", + "@hyperlane-xyz/utils": "5.6.0", "@inquirer/prompts": "^3.0.0", "ansi-escapes": "^7.0.0", "asn1.js": "^5.4.1", @@ -47,7 +47,8 @@ "clean": "rm -rf ./dist", "lint": "eslint . --ext .ts", "prettier": "prettier --write ./src ./examples", - "test:ci": "./scripts/all-test.sh", + "test:ci": "yarn mocha --config .mocharc.json", + "test:e2e": "./scripts/run-e2e-test.sh", "version:update": "echo \"export const VERSION = '$npm_package_version';\" > src/version.ts" }, "files": [ diff --git a/typescript/cli/scripts/all-test.sh b/typescript/cli/scripts/run-e2e-test.sh similarity index 71% rename from typescript/cli/scripts/all-test.sh rename to typescript/cli/scripts/run-e2e-test.sh index f33060987..e398253b2 100755 --- a/typescript/cli/scripts/all-test.sh +++ b/typescript/cli/scripts/run-e2e-test.sh @@ -1,24 +1,24 @@ #!/usr/bin/env bash function cleanup() { - set +e + set +e pkill -f anvil rm -rf /tmp/anvil2 rm -rf /tmp/anvil3 rm -f ./test-configs/anvil/chains/anvil2/addresses.yaml rm -f ./test-configs/anvil/chains/anvil3/addresses.yaml - set -e + set -e } cleanup -echo "Starting anvil2 and anvil3 chain" +echo "Starting anvil2 and anvil3 chain for E2E tests" anvil --chain-id 31338 -p 8555 --state /tmp/anvil2/state --gas-price 1 > /dev/null & anvil --chain-id 31347 -p 8600 --state /tmp/anvil3/state --gas-price 1 > /dev/null & -echo "Running all tests" -yarn mocha --config .mocharc.json +echo "Running E2E tests" +yarn mocha --config .mocharc-e2e.json cleanup -echo "Done all tests" \ No newline at end of file +echo "Completed E2E tests" diff --git a/typescript/cli/src/commands/core.ts b/typescript/cli/src/commands/core.ts index f691de750..60d84f877 100644 --- a/typescript/cli/src/commands/core.ts +++ b/typescript/cli/src/commands/core.ts @@ -1,10 +1,13 @@ +import { stringify as yamlStringify } from 'yaml'; import { CommandModule } from 'yargs'; import { + CoreConfig, DeployedCoreAddresses, DeployedCoreAddressesSchema, - EvmCoreReader, + normalizeConfig, } from '@hyperlane-xyz/sdk'; +import { diffObjMerge } from '@hyperlane-xyz/utils'; import { createCoreDeployConfig, @@ -16,17 +19,21 @@ import { } from '../context/types.js'; import { runCoreApply, runCoreDeploy } from '../deploy/core.js'; import { evaluateIfDryRunFailure } from '../deploy/dry-run.js'; -import { errorRed, log, logGray, logGreen } from '../logger.js'; +import { log, logCommandHeader, logGreen } from '../logger.js'; +import { executeCoreRead } from '../read/core.js'; import { logYamlIfUnderMaxLines, readYamlOrJson, writeYamlOrJson, } from '../utils/files.js'; +import { formatYamlViolationsOutput } from '../utils/output.js'; import { + DEFAULT_CORE_DEPLOYMENT_CONFIG_PATH, chainCommandOption, dryRunCommandOption, fromAddressCommandOption, + inputFileCommandOption, outputFileCommandOption, skipConfirmationOption, } from './options.js'; @@ -40,6 +47,7 @@ export const coreCommand: CommandModule = { builder: (yargs) => yargs .command(apply) + .command(check) .command(deploy) .command(init) .command(read) @@ -47,6 +55,7 @@ export const coreCommand: CommandModule = { .demandCommand(), handler: () => log('Command required'), }; + export const apply: CommandModuleWithWriteContext<{ chain: string; config: string; @@ -60,14 +69,13 @@ export const apply: CommandModuleWithWriteContext<{ demandOption: true, }, config: outputFileCommandOption( - './configs/core-config.yaml', + DEFAULT_CORE_DEPLOYMENT_CONFIG_PATH, true, 'The path to output a Core Config JSON or YAML file.', ), }, handler: async ({ context, chain, config: configFilePath }) => { - logGray(`Hyperlane Core Apply`); - logGray('--------------------'); + logCommandHeader(`Hyperlane Core Apply`); const addresses = (await context.registry.getChainAddresses( chain, @@ -103,7 +111,7 @@ export const deploy: CommandModuleWithWriteContext<{ builder: { chain: chainCommandOption, config: outputFileCommandOption( - './configs/core-config.yaml', + DEFAULT_CORE_DEPLOYMENT_CONFIG_PATH, false, 'The path to a JSON or YAML file with a core deployment config.', ), @@ -112,8 +120,7 @@ export const deploy: CommandModuleWithWriteContext<{ 'skip-confirmation': skipConfirmationOption, }, handler: async ({ context, chain, config: configFilePath, dryRun }) => { - logGray(`Hyperlane Core deployment${dryRun ? ' dry-run' : ''}`); - logGray(`------------------------------------------------`); + logCommandHeader(`Hyperlane Core deployment${dryRun ? ' dry-run' : ''}`); try { await runCoreDeploy({ @@ -142,14 +149,13 @@ export const init: CommandModuleWithContext<{ default: false, }, config: outputFileCommandOption( - './configs/core-config.yaml', + DEFAULT_CORE_DEPLOYMENT_CONFIG_PATH, false, 'The path to output a Core Config JSON or YAML file.', ), }, handler: async ({ context, advanced, config: configFilePath }) => { - logGray('Hyperlane Core Configure'); - logGray('------------------------'); + logCommandHeader('Hyperlane Core Configure'); await createCoreDeployConfig({ context, @@ -178,39 +184,70 @@ export const read: CommandModuleWithContext<{ description: 'Mailbox address used to derive the core config', }, config: outputFileCommandOption( - './configs/core-config.yaml', + DEFAULT_CORE_DEPLOYMENT_CONFIG_PATH, false, 'The path to output a Core Config JSON or YAML file.', ), }, handler: async ({ context, chain, mailbox, config: configFilePath }) => { - if (!mailbox) { - const addresses = await context.registry.getChainAddresses(chain); - mailbox = addresses?.mailbox; - if (!mailbox) { - throw new Error( - `${chain} mailbox not provided and none found in registry.`, - ); - } - } + logCommandHeader('Hyperlane Core Read'); - logGray('Hyperlane Core Read'); - logGray('-------------------'); + const coreConfig = await executeCoreRead({ context, chain, mailbox }); - const evmCoreReader = new EvmCoreReader(context.multiProvider, chain); - try { - const coreConfig = await evmCoreReader.deriveCoreConfig(mailbox); - writeYamlOrJson(configFilePath, coreConfig, 'yaml'); - logGreen(`✅ Core config written successfully to ${configFilePath}:\n`); - logYamlIfUnderMaxLines(coreConfig); - } catch (e: any) { - errorRed( - `❌ Failed to read core config for mailbox ${mailbox} on ${chain}:`, - e, - ); + writeYamlOrJson(configFilePath, coreConfig, 'yaml'); + logGreen(`✅ Core config written successfully to ${configFilePath}:\n`); + logYamlIfUnderMaxLines(coreConfig); + + process.exit(0); + }, +}; + +export const check: CommandModuleWithContext<{ + chain: string; + config: string; + mailbox?: string; +}> = { + command: 'check', + describe: + 'Reads onchain Core configuration for a given mailbox address and compares it with a provided file', + builder: { + chain: { + ...chainCommandOption, + demandOption: true, + }, + mailbox: { + type: 'string', + description: + 'Mailbox address used to derive the core config. If not provided it will be inferred from the registry', + }, + config: inputFileCommandOption({ + defaultPath: DEFAULT_CORE_DEPLOYMENT_CONFIG_PATH, + description: 'The path to a a Core Config JSON or YAML file.', + demandOption: false, + }), + }, + handler: async ({ context, chain, mailbox, config: configFilePath }) => { + logCommandHeader('Hyperlane Core Check'); + + const expectedCoreConfig: CoreConfig = await readYamlOrJson(configFilePath); + const onChainCoreConfig = await executeCoreRead({ + context, + chain, + mailbox, + }); + + const { mergedObject, isInvalid } = diffObjMerge( + normalizeConfig(onChainCoreConfig), + normalizeConfig(expectedCoreConfig), + ); + + if (isInvalid) { + log(formatYamlViolationsOutput(yamlStringify(mergedObject, null, 2))); process.exit(1); } + logGreen(`No violations found`); + process.exit(0); }, }; diff --git a/typescript/cli/src/commands/options.ts b/typescript/cli/src/commands/options.ts index 218671509..f23194c80 100644 --- a/typescript/cli/src/commands/options.ts +++ b/typescript/cli/src/commands/options.ts @@ -94,6 +94,8 @@ export const hookCommandOption: Options = { export const DEFAULT_WARP_ROUTE_DEPLOYMENT_CONFIG_PATH = './configs/warp-route-deployment.yaml'; +export const DEFAULT_CORE_DEPLOYMENT_CONFIG_PATH = './configs/core-config.yaml'; + export const warpDeploymentConfigCommandOption: Options = { type: 'string', description: diff --git a/typescript/cli/src/config/chain.ts b/typescript/cli/src/config/chain.ts index 199e026c8..e710b6cf0 100644 --- a/typescript/cli/src/config/chain.ts +++ b/typescript/cli/src/config/chain.ts @@ -5,6 +5,7 @@ import { stringify as yamlStringify } from 'yaml'; import { ChainMetadata, ChainMetadataSchema, + EthJsonRpcBlockParameterTag, ExplorerFamily, ZChainName, } from '@hyperlane-xyz/sdk'; @@ -168,6 +169,13 @@ async function addBlockOrGasConfig(metadata: ChainMetadata): Promise { } async function addBlockConfig(metadata: ChainMetadata): Promise { + const parseReorgPeriod = ( + value: string, + ): number | EthJsonRpcBlockParameterTag => { + const parsed = parseInt(value, 10); + return isNaN(parsed) ? (value as EthJsonRpcBlockParameterTag) : parsed; + }; + const wantBlockConfig = await confirm({ message: 'Do you want to add block config for this chain', }); @@ -179,8 +187,16 @@ async function addBlockConfig(metadata: ChainMetadata): Promise { }); const blockReorgPeriod = await input({ message: - 'Enter no. of blocks before a transaction has a near-zero chance of reverting (0-500):', - validate: (value) => parseInt(value) >= 0 && parseInt(value) <= 500, + 'Enter no. of blocks before a transaction has a near-zero chance of reverting (0-500) or block tag (earliest, latest, safe, finalized, pending):', + validate: (value) => { + const parsedInt = parseInt(value, 10); + return ( + Object.values(EthJsonRpcBlockParameterTag).includes( + value as EthJsonRpcBlockParameterTag, + ) || + (!isNaN(parsedInt) && parsedInt >= 0 && parsedInt <= 500) + ); + }, }); const blockTimeEstimate = await input({ message: 'Enter the rough estimate of time per block in seconds (0-20):', @@ -188,7 +204,7 @@ async function addBlockConfig(metadata: ChainMetadata): Promise { }); metadata.blocks = { confirmations: parseInt(blockConfirmation, 10), - reorgPeriod: parseInt(blockReorgPeriod, 10), + reorgPeriod: parseReorgPeriod(blockReorgPeriod), estimateBlockTime: parseInt(blockTimeEstimate, 10), }; } diff --git a/typescript/cli/src/read/core.ts b/typescript/cli/src/read/core.ts new file mode 100644 index 000000000..b7f1f94b2 --- /dev/null +++ b/typescript/cli/src/read/core.ts @@ -0,0 +1,36 @@ +import { ChainName, CoreConfig, EvmCoreReader } from '@hyperlane-xyz/sdk'; +import { Address, assert } from '@hyperlane-xyz/utils'; + +import { CommandContext } from '../context/types.js'; +import { errorRed } from '../logger.js'; + +export async function executeCoreRead({ + context, + chain, + mailbox, +}: { + context: CommandContext; + chain: ChainName; + mailbox?: Address; +}): Promise { + if (!mailbox) { + const addresses = await context.registry.getChainAddresses(chain); + mailbox = addresses?.mailbox; + + assert( + mailbox, + `${chain} mailbox not provided and none found in registry.`, + ); + } + + const evmCoreReader = new EvmCoreReader(context.multiProvider, chain); + try { + return evmCoreReader.deriveCoreConfig(mailbox); + } catch (e: any) { + errorRed( + `❌ Failed to read core config for mailbox ${mailbox} on ${chain}:`, + e, + ); + process.exit(1); + } +} diff --git a/typescript/cli/src/version.ts b/typescript/cli/src/version.ts index ce5c04eb3..d4a8ed991 100644 --- a/typescript/cli/src/version.ts +++ b/typescript/cli/src/version.ts @@ -1 +1 @@ -export const VERSION = '5.5.0'; +export const VERSION = '5.6.0'; diff --git a/typescript/github-proxy/CHANGELOG.md b/typescript/github-proxy/CHANGELOG.md index a22fdc8ab..a71264e35 100644 --- a/typescript/github-proxy/CHANGELOG.md +++ b/typescript/github-proxy/CHANGELOG.md @@ -1,5 +1,7 @@ # @hyperlane-xyz/github-proxy +## 5.6.0 + ## 5.5.0 ## 5.4.0 diff --git a/typescript/github-proxy/package.json b/typescript/github-proxy/package.json index cefc3c0dc..d8173c30d 100644 --- a/typescript/github-proxy/package.json +++ b/typescript/github-proxy/package.json @@ -1,7 +1,7 @@ { "name": "@hyperlane-xyz/github-proxy", "description": "Github proxy that adds the API key to requests", - "version": "5.5.0", + "version": "5.6.0", "private": true, "scripts": { "deploy": "wrangler deploy", diff --git a/typescript/helloworld/CHANGELOG.md b/typescript/helloworld/CHANGELOG.md index aac142144..1d2f1535b 100644 --- a/typescript/helloworld/CHANGELOG.md +++ b/typescript/helloworld/CHANGELOG.md @@ -1,5 +1,27 @@ # @hyperlane-xyz/helloworld +## 5.6.0 + +### Patch Changes + +- e89f9e35d: Update registry to v4.7.0 +- Updated dependencies [46044a2e9] +- Updated dependencies [02a5b92ba] +- Updated dependencies [29341950e] +- Updated dependencies [8001bbbd6] +- Updated dependencies [32d0a67c2] +- Updated dependencies [c9085afd9] +- Updated dependencies [b1ff48bd1] +- Updated dependencies [d41aa6928] +- Updated dependencies [ec6b874b1] +- Updated dependencies [c3e9268f1] +- Updated dependencies [72c23c0d6] +- Updated dependencies [7d7bcc1a3] +- Updated dependencies [7f3e0669d] +- Updated dependencies [2317eca3c] + - @hyperlane-xyz/sdk@5.6.0 + - @hyperlane-xyz/core@5.5.0 + ## 5.5.0 ### Patch Changes diff --git a/typescript/helloworld/package.json b/typescript/helloworld/package.json index ca2d79f60..927647d06 100644 --- a/typescript/helloworld/package.json +++ b/typescript/helloworld/package.json @@ -1,11 +1,11 @@ { "name": "@hyperlane-xyz/helloworld", "description": "A basic skeleton of an Hyperlane app", - "version": "5.5.0", + "version": "5.6.0", "dependencies": { - "@hyperlane-xyz/core": "5.4.1", + "@hyperlane-xyz/core": "5.5.0", "@hyperlane-xyz/registry": "4.7.0", - "@hyperlane-xyz/sdk": "5.5.0", + "@hyperlane-xyz/sdk": "5.6.0", "@openzeppelin/contracts-upgradeable": "^4.9.3", "ethers": "^5.7.2" }, diff --git a/typescript/infra/CHANGELOG.md b/typescript/infra/CHANGELOG.md index bd6476484..3b623135c 100644 --- a/typescript/infra/CHANGELOG.md +++ b/typescript/infra/CHANGELOG.md @@ -1,5 +1,31 @@ # @hyperlane-xyz/infra +## 5.6.0 + +### Minor Changes + +- b3495b205: Updates the warpIds for Renzo's latest deployment to Sei and Taiko to be used by the Checker +- c3e9268f1: Add support for an arbitrary string in `reorgPeriod`, which is used as a block tag to get the finalized block. + +### Patch Changes + +- Updated dependencies [f1712deb7] +- Updated dependencies [46044a2e9] +- Updated dependencies [02a5b92ba] +- Updated dependencies [29341950e] +- Updated dependencies [8001bbbd6] +- Updated dependencies [32d0a67c2] +- Updated dependencies [b1ff48bd1] +- Updated dependencies [e89f9e35d] +- Updated dependencies [d41aa6928] +- Updated dependencies [c3e9268f1] +- Updated dependencies [7d7bcc1a3] +- Updated dependencies [7f3e0669d] +- Updated dependencies [2317eca3c] + - @hyperlane-xyz/utils@5.6.0 + - @hyperlane-xyz/sdk@5.6.0 + - @hyperlane-xyz/helloworld@5.6.0 + ## 5.5.0 ### Patch Changes diff --git a/typescript/infra/config/environments/mainnet3/agent.ts b/typescript/infra/config/environments/mainnet3/agent.ts index 6b6f2bae5..fa21db977 100644 --- a/typescript/infra/config/environments/mainnet3/agent.ts +++ b/typescript/infra/config/environments/mainnet3/agent.ts @@ -115,6 +115,7 @@ export const hyperlaneContextAgentChainConfig: AgentChainConfig< sei: true, shibarium: true, solanamainnet: true, + stride: false, superposition: true, taiko: true, tangle: true, @@ -189,6 +190,7 @@ export const hyperlaneContextAgentChainConfig: AgentChainConfig< sei: true, shibarium: true, solanamainnet: true, + stride: true, superposition: true, taiko: true, tangle: true, @@ -264,6 +266,7 @@ export const hyperlaneContextAgentChainConfig: AgentChainConfig< shibarium: true, // Cannot scrape Sealevel chains solanamainnet: false, + stride: true, superposition: true, taiko: true, tangle: true, @@ -418,7 +421,7 @@ const hyperlane: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: 'b1ff48b-20241016-183301', + tag: '42d6b50-20241021-155906', }, gasPaymentEnforcement: gasPaymentEnforcement, metricAppContexts, @@ -437,7 +440,7 @@ const hyperlane: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: '9c0c4bb-20241018-113820', + tag: '42d6b50-20241021-155906', }, resources: scraperResources, }, @@ -452,7 +455,7 @@ const releaseCandidate: RootAgentConfig = { rpcConsensusType: RpcConsensusType.Fallback, docker: { repo, - tag: 'b1ff48b-20241016-183301', + tag: '42d6b50-20241021-155906', }, // We're temporarily (ab)using the RC relayer as a way to increase // message throughput. diff --git a/typescript/infra/config/environments/mainnet3/funding.ts b/typescript/infra/config/environments/mainnet3/funding.ts index dafee524d..e69298dc3 100644 --- a/typescript/infra/config/environments/mainnet3/funding.ts +++ b/typescript/infra/config/environments/mainnet3/funding.ts @@ -82,6 +82,8 @@ export const keyFunderConfig: KeyFunderConfig< scroll: '0.5', sei: '50', shibarium: '50', + // ignore non-evm chains + stride: '0', superposition: '0.05', taiko: '0.2', tangle: '2', diff --git a/typescript/infra/config/environments/mainnet3/gasPrices.json b/typescript/infra/config/environments/mainnet3/gasPrices.json index d68a6d290..7f61122c8 100644 --- a/typescript/infra/config/environments/mainnet3/gasPrices.json +++ b/typescript/infra/config/environments/mainnet3/gasPrices.json @@ -243,6 +243,10 @@ "amount": "0.5", "decimals": 1 }, + "stride": { + "amount": "0.005", + "decimals": 1 + }, "superposition": { "amount": "0.01", "decimals": 9 diff --git a/typescript/infra/config/environments/mainnet3/supportedChainNames.ts b/typescript/infra/config/environments/mainnet3/supportedChainNames.ts index c5eabc80c..3e5957241 100644 --- a/typescript/infra/config/environments/mainnet3/supportedChainNames.ts +++ b/typescript/infra/config/environments/mainnet3/supportedChainNames.ts @@ -62,6 +62,7 @@ export const mainnet3SupportedChainNames = [ 'sei', 'shibarium', 'solanamainnet', + 'stride', 'superposition', 'taiko', 'tangle', diff --git a/typescript/infra/config/environments/mainnet3/tokenPrices.json b/typescript/infra/config/environments/mainnet3/tokenPrices.json index df245702e..86c2ed731 100644 --- a/typescript/infra/config/environments/mainnet3/tokenPrices.json +++ b/typescript/infra/config/environments/mainnet3/tokenPrices.json @@ -60,6 +60,7 @@ "sei": "0.447635", "shibarium": "0.410927", "solanamainnet": "155.35", + "stride": "0.840153", "superposition": "2629.74", "taiko": "2629.74", "tangle": "1", diff --git a/typescript/infra/config/environments/mainnet3/warp/AMPHRETH-deployments.yaml b/typescript/infra/config/environments/mainnet3/warp/AMPHRETH-deployments.yaml new file mode 100644 index 000000000..222a321c2 --- /dev/null +++ b/typescript/infra/config/environments/mainnet3/warp/AMPHRETH-deployments.yaml @@ -0,0 +1,28 @@ +# Configs and artifacts for the deployment of Hyperlane Warp Routes +description: Hyperlane Warp Route artifacts +timestamp: '2024-10-18T14:00:00.000Z' +deployer: Abacus Works (Hyperlane) +data: + config: + arbitrum: + protocolType: ethereum + type: synthetic + hypAddress: '0x6D251aADfc6Ff69031e01eA39bE3cb5BABf8438f' + name: Amphor Restaked ETH + symbol: AMPHRETH + decimals: 18 + ethereum: + protocolType: ethereum + type: collateral + hypAddress: '0xdc89990a6fdC1C922b841f1d977835628A24Ed57' + tokenAddress: '0x5fD13359Ba15A84B76f7F87568309040176167cd' + name: Amphor Restaked ETH + symbol: AMPHRETH + decimals: 18 + zircuit: + protocolType: ethereum + type: synthetic + hypAddress: '0x7D5a79539d7B1c9aE5e54d18EEE188840f1Fe4CC' + name: Amphor Restaked ETH + symbol: AMPHRETH + decimals: 18 diff --git a/typescript/infra/config/environments/mainnet3/warp/configGetters/getArbitrumEthereumZircuitAmphrETHWarpConfig.ts b/typescript/infra/config/environments/mainnet3/warp/configGetters/getArbitrumEthereumZircuitAmphrETHWarpConfig.ts new file mode 100644 index 000000000..1b81e8110 --- /dev/null +++ b/typescript/infra/config/environments/mainnet3/warp/configGetters/getArbitrumEthereumZircuitAmphrETHWarpConfig.ts @@ -0,0 +1,55 @@ +import { ethers } from 'ethers'; + +import { + ChainMap, + RouterConfig, + TokenRouterConfig, + TokenType, +} from '@hyperlane-xyz/sdk'; + +import { tokens } from '../../../../../src/config/warp.js'; + +const arbitrumOwner = '0x008615770B588633265cB01Abd19740fAe67d0B9'; +const ethereumOwner = '0x008615770B588633265cB01Abd19740fAe67d0B9'; +const zircuitOwner = '0xD0673e7F3FB4037CA79F53d2d311D0e017d39963'; + +export const getArbitrumEthereumZircuitAmphrETHWarpConfig = async ( + routerConfig: ChainMap, +): Promise> => { + const arbitrum: TokenRouterConfig = { + ...routerConfig.arbitrum, + type: TokenType.synthetic, + interchainSecurityModule: ethers.constants.AddressZero, + owner: arbitrumOwner, + ownerOverrides: { + proxyAdmin: arbitrumOwner, + }, + }; + + const ethereum: TokenRouterConfig = { + ...routerConfig.ethereum, + type: TokenType.collateral, + token: tokens.ethereum.amphrETH, + owner: ethereumOwner, + interchainSecurityModule: ethers.constants.AddressZero, + ownerOverrides: { + proxyAdmin: ethereumOwner, + }, + }; + + const zircuit: TokenRouterConfig = { + ...routerConfig.zircuit, + type: TokenType.synthetic, + interchainSecurityModule: ethers.constants.AddressZero, + owner: zircuitOwner, + ownerOverrides: { + proxyAdmin: zircuitOwner, + }, + }; + + return { + arbitrum, + ethereum, + zircuit, + }; +}; diff --git a/typescript/infra/config/environments/mainnet3/warp/warpIds.ts b/typescript/infra/config/environments/mainnet3/warp/warpIds.ts index 9ff51677e..debc81326 100644 --- a/typescript/infra/config/environments/mainnet3/warp/warpIds.ts +++ b/typescript/infra/config/environments/mainnet3/warp/warpIds.ts @@ -1,6 +1,7 @@ export enum WarpRouteIds { Ancient8EthereumUSDC = 'USDC/ancient8-ethereum', ArbitrumBaseBlastBscEthereumFraxtalLineaModeOptimismSeiTaikoZircuitEZETH = 'EZETH/arbitrum-base-blast-bsc-ethereum-fraxtal-linea-mode-optimism-sei-taiko-zircuit', + ArbitrumEthereumZircuitAMPHRETH = 'AMPHRETH/arbitrum-ethereum-zircuit', ArbitrumNeutronEclip = 'ECLIP/arbitrum-neutron', ArbitrumNeutronTIA = 'TIA/arbitrum-neutron', EclipseSolanaSOL = 'SOL/eclipsemainnet-solanamainnet', diff --git a/typescript/infra/config/registry.ts b/typescript/infra/config/registry.ts index 51ac87729..4b72c9f5b 100644 --- a/typescript/infra/config/registry.ts +++ b/typescript/infra/config/registry.ts @@ -78,7 +78,7 @@ export function getDomainId(chainName: ChainName): number { return resolveDomainId(chain); } -export function getReorgPeriod(chainName: ChainName): number { +export function getReorgPeriod(chainName: ChainName): string | number { const chain = getChain(chainName); return resolveReorgPeriod(chain); } diff --git a/typescript/infra/config/warp.ts b/typescript/infra/config/warp.ts index 447183e8c..2b7c44ee4 100644 --- a/typescript/infra/config/warp.ts +++ b/typescript/infra/config/warp.ts @@ -9,6 +9,7 @@ import { getHyperlaneCore } from '../scripts/core-utils.js'; import { EnvironmentConfig } from '../src/config/environment.js'; import { getAncient8EthereumUSDCWarpConfig } from './environments/mainnet3/warp/configGetters/getAncient8EthereumUSDCWarpConfig.js'; +import { getArbitrumEthereumZircuitAmphrETHWarpConfig } from './environments/mainnet3/warp/configGetters/getArbitrumEthereumZircuitAmphrETHWarpConfig.js'; import { getArbitrumNeutronEclipWarpConfig } from './environments/mainnet3/warp/configGetters/getArbitrumNeutronEclipWarpConfig.js'; import { getArbitrumNeutronTiaWarpConfig } from './environments/mainnet3/warp/configGetters/getArbitrumNeutronTiaWarpConfig.js'; import { getEthereumInevmUSDCWarpConfig } from './environments/mainnet3/warp/configGetters/getEthereumInevmUSDCWarpConfig.js'; @@ -34,6 +35,8 @@ export const warpConfigGetterMap: Record< WarpConfigGetterWithConfig | WarpConfigGetterWithoutConfig > = { [WarpRouteIds.Ancient8EthereumUSDC]: getAncient8EthereumUSDCWarpConfig, + [WarpRouteIds.ArbitrumEthereumZircuitAMPHRETH]: + getArbitrumEthereumZircuitAmphrETHWarpConfig, [WarpRouteIds.EthereumInevmUSDC]: getEthereumInevmUSDCWarpConfig, [WarpRouteIds.EthereumInevmUSDT]: getEthereumInevmUSDTWarpConfig, [WarpRouteIds.ArbitrumNeutronEclip]: getArbitrumNeutronEclipWarpConfig, diff --git a/typescript/infra/package.json b/typescript/infra/package.json index d49058100..9d1d090c5 100644 --- a/typescript/infra/package.json +++ b/typescript/infra/package.json @@ -1,7 +1,7 @@ { "name": "@hyperlane-xyz/infra", "description": "Infrastructure utilities for the Hyperlane Network", - "version": "5.5.0", + "version": "5.6.0", "dependencies": { "@arbitrum/sdk": "^3.0.0", "@aws-sdk/client-iam": "^3.74.0", @@ -13,10 +13,10 @@ "@ethersproject/hardware-wallets": "^5.7.0", "@ethersproject/providers": "^5.7.2", "@google-cloud/secret-manager": "^5.5.0", - "@hyperlane-xyz/helloworld": "5.5.0", + "@hyperlane-xyz/helloworld": "5.6.0", "@hyperlane-xyz/registry": "4.7.0", - "@hyperlane-xyz/sdk": "5.5.0", - "@hyperlane-xyz/utils": "5.5.0", + "@hyperlane-xyz/sdk": "5.6.0", + "@hyperlane-xyz/utils": "5.6.0", "@inquirer/prompts": "^5.3.8", "@nomiclabs/hardhat-etherscan": "^3.0.3", "@safe-global/api-kit": "1.3.0", diff --git a/typescript/infra/src/config/agent/validator.ts b/typescript/infra/src/config/agent/validator.ts index 05293abfa..e18220017 100644 --- a/typescript/infra/src/config/agent/validator.ts +++ b/typescript/infra/src/config/agent/validator.ts @@ -26,8 +26,8 @@ export type ValidatorBaseChainConfigMap = ChainMap; export interface ValidatorBaseChainConfig { // How frequently to check for new checkpoints interval: number; - // The reorg_period in blocks; overrides chain metadata - reorgPeriod: number; + // The reorg_period in blocks or block tag; overrides chain metadata + reorgPeriod: string | number; // Individual validator agents validators: Array; } diff --git a/typescript/infra/src/config/warp.ts b/typescript/infra/src/config/warp.ts index 25bd40818..d66aed2fc 100644 --- a/typescript/infra/src/config/warp.ts +++ b/typescript/infra/src/config/warp.ts @@ -7,6 +7,7 @@ export const tokens: ChainMap> = { USDC: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', USDT: '0xdac17f958d2ee523a2206206994597c13d831ec7', deUSD: '0x15700B564Ca08D9439C58cA5053166E8317aa138', + amphrETH: '0x5fD13359Ba15A84B76f7F87568309040176167cd', }, sei: { fastUSD: '0x37a4dD9CED2b19Cfe8FAC251cd727b5787E45269', diff --git a/typescript/infra/src/govern/HyperlaneAppGovernor.ts b/typescript/infra/src/govern/HyperlaneAppGovernor.ts index d35a1499f..893a25c71 100644 --- a/typescript/infra/src/govern/HyperlaneAppGovernor.ts +++ b/typescript/infra/src/govern/HyperlaneAppGovernor.ts @@ -166,17 +166,23 @@ export abstract class HyperlaneAppGovernor< // If calls are being submitted via a safe, we need to check for any safe owner changes first if (submissionType === SubmissionType.SAFE) { - const { safeSdk } = await getSafeAndService( - chain, - this.checker.multiProvider, - (multiSend as SafeMultiSend).safeAddress, - ); - const updateOwnerCalls = await updateSafeOwner(safeSdk); - callsForSubmissionType.push(...updateOwnerCalls, ...filteredCalls); - } else { - callsForSubmissionType.push(...filteredCalls); + try { + const { safeSdk } = await getSafeAndService( + chain, + this.checker.multiProvider, + (multiSend as SafeMultiSend).safeAddress, + ); + const updateOwnerCalls = await updateSafeOwner(safeSdk); + callsForSubmissionType.push(...updateOwnerCalls); + } catch (error) { + // Catch but don't throw because we want to try submitting any remaining calls + console.error(`Error updating safe owner: ${error}`); + } } + // Add the filtered calls to the calls for submission type + callsForSubmissionType.push(...filteredCalls); + if (callsForSubmissionType.length > 0) { this.printSeparator(); const confirmed = await summarizeCalls( diff --git a/typescript/infra/src/warp/helm.ts b/typescript/infra/src/warp/helm.ts index 4633ddd83..f5aa0e981 100644 --- a/typescript/infra/src/warp/helm.ts +++ b/typescript/infra/src/warp/helm.ts @@ -27,7 +27,7 @@ export class WarpRouteMonitorHelmManager extends HelmManager { return { image: { repository: 'gcr.io/abacus-labs-dev/hyperlane-monorepo', - tag: 'd4d5501-20240925-222735', + tag: '6945b20-20241022-155935', }, configFilePath: pathRelativeToMonorepoRoot, fullnameOverride: this.helmReleaseName, diff --git a/typescript/sdk/CHANGELOG.md b/typescript/sdk/CHANGELOG.md index 058f6b817..0cec012ff 100644 --- a/typescript/sdk/CHANGELOG.md +++ b/typescript/sdk/CHANGELOG.md @@ -1,5 +1,31 @@ # @hyperlane-xyz/sdk +## 5.6.0 + +### Minor Changes + +- 46044a2e9: Deploy to odysseytestnet +- 02a5b92ba: Enroll new validators. Add tx overrides when deploying ICA accounts. Core checker now surfaces owner violations for defaultHook and requiredHook. App checker temporarily ignores bytecode mismatch violations. +- 29341950e: Adds new `core check` command to compare local configuration and on chain deployments. Adds memoization to the EvmHookReader to avoid repeating configuration derivation +- 8001bbbd6: Add override to some transactions to fix warp apply +- 32d0a67c2: Adds the warp check command to compare warp routes config files with on chain warp route deployments +- b1ff48bd1: Add rebasing yield route support into CLI/SDK +- d41aa6928: Add `EthJsonRpcBlockParameterTag` enum for validating reorgPeriod +- c3e9268f1: Add support for an arbitrary string in `reorgPeriod`, which is used as a block tag to get the finalized block. +- 7d7bcc1a3: Add deployments for mainnets: flow, metall2, polynomial + +### Patch Changes + +- 7f3e0669d: Fix filtering non-evm addresses in appFromAddressesMapHelper +- 2317eca3c: Set transaction overrides and add 10% gas limit buffer when sending message through HyperlaneCore. +- Updated dependencies [f1712deb7] +- Updated dependencies [29341950e] +- Updated dependencies [c9085afd9] +- Updated dependencies [ec6b874b1] +- Updated dependencies [72c23c0d6] + - @hyperlane-xyz/utils@5.6.0 + - @hyperlane-xyz/core@5.5.0 + ## 5.5.0 ### Minor Changes diff --git a/typescript/sdk/package.json b/typescript/sdk/package.json index 6290277c8..1a5e86aa8 100644 --- a/typescript/sdk/package.json +++ b/typescript/sdk/package.json @@ -1,14 +1,14 @@ { "name": "@hyperlane-xyz/sdk", "description": "The official SDK for the Hyperlane Network", - "version": "5.5.0", + "version": "5.6.0", "dependencies": { "@arbitrum/sdk": "^4.0.0", "@aws-sdk/client-s3": "^3.74.0", "@cosmjs/cosmwasm-stargate": "^0.32.4", "@cosmjs/stargate": "^0.32.4", - "@hyperlane-xyz/core": "5.4.1", - "@hyperlane-xyz/utils": "5.5.0", + "@hyperlane-xyz/core": "5.5.0", + "@hyperlane-xyz/utils": "5.6.0", "@safe-global/api-kit": "1.3.0", "@safe-global/protocol-kit": "1.3.0", "@safe-global/safe-deployments": "1.37.8", diff --git a/typescript/sdk/src/contracts/contracts.ts b/typescript/sdk/src/contracts/contracts.ts index 90b754e8c..5f1913a55 100644 --- a/typescript/sdk/src/contracts/contracts.ts +++ b/typescript/sdk/src/contracts/contracts.ts @@ -1,4 +1,4 @@ -import { Contract, ethers } from 'ethers'; +import { Contract } from 'ethers'; import { Ownable } from '@hyperlane-xyz/core'; import { @@ -235,31 +235,15 @@ export function appFromAddressesMapHelper( contractsMap: HyperlaneContractsMap; multiProvider: MultiProvider; } { - // Hack to accommodate non-Ethereum artifacts, while still retaining their - // presence in the addressesMap so that they are included in the list of chains - // on the MultiProvider (needed for getting metadata). A non-Ethereum-style address - // from another execution environment will cause Ethers to throw if we try to attach - // it, so we just replace it with the zero address. - const addressesMapWithEthereumizedAddresses = objMap( + // Filter out non-Ethereum chains from the addressesMap + const ethereumAddressesMap = objFilter( addressesMap, - (chain, addresses) => { - const metadata = multiProvider.getChainMetadata(chain); - if (metadata.protocol === ProtocolType.Ethereum) { - return addresses; - } - return objMap( - addresses, - (_key, _address) => ethers.constants.AddressZero, - ); - }, + (chain, _): _ is HyperlaneAddresses => + multiProvider.getProtocol(chain) === ProtocolType.Ethereum, ); - // Attaches contracts for each chain for which we have a complete set of - // addresses - const contractsMap = attachContractsMap( - addressesMapWithEthereumizedAddresses, - factories, - ); + // Attaches contracts for each Ethereum chain for which we have a complete set of addresses + const contractsMap = attachContractsMap(ethereumAddressesMap, factories); // Filters out providers for chains for which we don't have a complete set // of addresses @@ -270,6 +254,6 @@ export function appFromAddressesMapHelper( return { contractsMap: filteredContractsMap, - multiProvider: multiProvider, + multiProvider, }; } diff --git a/typescript/sdk/src/hook/EvmHookReader.ts b/typescript/sdk/src/hook/EvmHookReader.ts index f54c4cf50..518b63e58 100644 --- a/typescript/sdk/src/hook/EvmHookReader.ts +++ b/typescript/sdk/src/hook/EvmHookReader.ts @@ -83,6 +83,12 @@ export interface HookReader { export class EvmHookReader extends HyperlaneReader implements HookReader { protected readonly logger = rootLogger.child({ module: 'EvmHookReader' }); + /** + * HookConfig cache for already retrieved configs. Useful to avoid recomputing configs + * when they have already been retrieved in previous calls where `deriveHookConfig` was called by + * the specific hook methods. + */ + private _cache: Map = new Map(); constructor( protected readonly multiProvider: MultiProvider, @@ -95,8 +101,23 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { } async deriveHookConfig(address: Address): Promise { + this.logger.debug('Deriving HookConfig:', { address }); + + const cachedValue = this._cache.get(address); + if (cachedValue) { + this.logger.debug( + `Cache hit for HookConfig on chain ${this.chain} at: ${address}`, + ); + return cachedValue; + } + + this.logger.debug( + `Cache miss for HookConfig on chain ${this.chain} at: ${address}`, + ); + let onchainHookType: OnchainHookType | undefined = undefined; let derivedHookConfig: DerivedHookConfig; + try { const hook = IPostDispatchHook__factory.connect(address, this.provider); this.logger.debug('Deriving HookConfig:', { address }); @@ -168,10 +189,14 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { const hook = MerkleTreeHook__factory.connect(address, this.provider); this.assertHookType(await hook.hookType(), OnchainHookType.MERKLE_TREE); - return { + const config: WithAddress = { address, type: HookType.MERKLE_TREE, }; + + this._cache.set(address, config); + + return config; } async deriveAggregationConfig( @@ -187,11 +212,15 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { (hook) => this.deriveHookConfig(hook), ); - return { + const config: WithAddress = { address, type: HookType.AGGREGATION, hooks: hookConfigs, }; + + this._cache.set(address, config); + + return config; } async deriveIgpConfig(address: Address): Promise> { @@ -259,7 +288,7 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { oracleKey = resolvedOracleKeys[0]; } - return { + const config: WithAddress = { owner, address, type: HookType.INTERCHAIN_GAS_PAYMASTER, @@ -268,6 +297,10 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { overhead, oracleConfig, }; + + this._cache.set(address, config); + + return config; } async deriveProtocolFeeConfig( @@ -281,7 +314,7 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { const protocolFee = await hook.protocolFee(); const beneficiary = await hook.beneficiary(); - return { + const config: WithAddress = { owner, address, type: HookType.PROTOCOL_FEE, @@ -289,6 +322,10 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { protocolFee: protocolFee.toString(), beneficiary, }; + + this._cache.set(address, config); + + return config; } async deriveOpStackConfig( @@ -303,13 +340,17 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { const destinationChainName = this.multiProvider.getChainName(destinationDomain); - return { + const config: WithAddress = { owner, address, type: HookType.OP_STACK, nativeBridge: messengerContract, destinationChain: destinationChainName, }; + + this._cache.set(address, config); + + return config; } async deriveArbL2ToL1Config( @@ -321,12 +362,17 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { const destinationDomain = await hook.destinationDomain(); const destinationChainName = this.multiProvider.getChainName(destinationDomain); - return { + + const config: WithAddress = { address, type: HookType.ARB_L2_TO_L1, destinationChain: destinationChainName, arbSys, }; + + this._cache.set(address, config); + + return config; } async deriveDomainRoutingConfig( @@ -338,12 +384,16 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { const owner = await hook.owner(); const domainHooks = await this.fetchDomainHooks(hook); - return { + const config: WithAddress = { owner, address, type: HookType.ROUTING, domains: domainHooks, }; + + this._cache.set(address, config); + + return config; } async deriveFallbackRoutingConfig( @@ -364,13 +414,17 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { const fallbackHook = await hook.fallbackHook(); const fallbackHookConfig = await this.deriveHookConfig(fallbackHook); - return { + const config: WithAddress = { owner, address, type: HookType.FALLBACK_ROUTING, domains: domainHooks, fallback: fallbackHookConfig, }; + + this._cache.set(address, config); + + return config; } private async fetchDomainHooks( @@ -406,12 +460,16 @@ export class EvmHookReader extends HyperlaneReader implements HookReader { const owner = await hook.owner(); const paused = await hook.paused(); - return { + const config: WithAddress = { owner, address, paused, type: HookType.PAUSABLE, }; + + this._cache.set(address, config); + + return config; } assertHookType( diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index a5fe295bb..23ba74578 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -197,6 +197,7 @@ export { export { BlockExplorer, BlockExplorerSchema, + EthJsonRpcBlockParameterTag, ChainMetadata, ChainMetadataSchema, ChainMetadataSchemaObject, diff --git a/typescript/sdk/src/metadata/chainMetadata.test.ts b/typescript/sdk/src/metadata/chainMetadata.test.ts index 773eb9c03..f38a59e46 100644 --- a/typescript/sdk/src/metadata/chainMetadata.test.ts +++ b/typescript/sdk/src/metadata/chainMetadata.test.ts @@ -2,7 +2,11 @@ import { expect } from 'chai'; import { ProtocolType } from '@hyperlane-xyz/utils'; -import { ChainMetadata, isValidChainMetadata } from './chainMetadataTypes.js'; +import { + ChainMetadata, + EthJsonRpcBlockParameterTag, + isValidChainMetadata, +} from './chainMetadataTypes.js'; const minimalSchema: ChainMetadata = { chainId: 5, @@ -62,6 +66,16 @@ describe('ChainMetadataSchema', () => { grpcUrls: [], }), ).to.eq(true); + + expect( + isValidChainMetadata({ + ...minimalSchema, + blocks: { + confirmations: 1, + reorgPeriod: EthJsonRpcBlockParameterTag.Finalized, + }, + }), + ).to.eq(true); }); it('Rejects invalid schemas', () => { diff --git a/typescript/sdk/src/metadata/chainMetadataTypes.ts b/typescript/sdk/src/metadata/chainMetadataTypes.ts index caf290ced..bf41cd4ac 100644 --- a/typescript/sdk/src/metadata/chainMetadataTypes.ts +++ b/typescript/sdk/src/metadata/chainMetadataTypes.ts @@ -10,6 +10,14 @@ import { ChainMap } from '../types.js'; import { ZChainName, ZNzUint, ZUint } from './customZodTypes.js'; +export enum EthJsonRpcBlockParameterTag { + Earliest = 'earliest', + Latest = 'latest', + Safe = 'safe', + Finalized = 'finalized', + Pending = 'pending', +} + export enum ExplorerFamily { Etherscan = 'etherscan', Blockscout = 'blockscout', @@ -125,9 +133,12 @@ export const ChainMetadataSchemaObject = z.object({ confirmations: ZUint.describe( 'Number of blocks to wait before considering a transaction confirmed.', ), - reorgPeriod: ZUint.optional().describe( - 'Number of blocks before a transaction has a near-zero chance of reverting.', - ), + reorgPeriod: z + .union([ZUint, z.string()]) + .optional() + .describe( + 'Number of blocks before a transaction has a near-zero chance of reverting or block tag.', + ), estimateBlockTime: z .number() .positive() @@ -371,7 +382,7 @@ export function getChainIdNumber(chainMetadata: ChainMetadata): number { else throw new Error('ChainId is not a number, chain may be of Cosmos type'); } -export function getReorgPeriod(chainMetadata: ChainMetadata): number { +export function getReorgPeriod(chainMetadata: ChainMetadata): string | number { if (chainMetadata.blocks?.reorgPeriod !== undefined) return chainMetadata.blocks.reorgPeriod; else throw new Error('Chain has no reorg period'); diff --git a/typescript/utils/CHANGELOG.md b/typescript/utils/CHANGELOG.md index a9252e563..e22dca07a 100644 --- a/typescript/utils/CHANGELOG.md +++ b/typescript/utils/CHANGELOG.md @@ -1,5 +1,15 @@ # @hyperlane-xyz/utils +## 5.6.0 + +### Minor Changes + +- 29341950e: Adds new `core check` command to compare local configuration and on chain deployments. Adds memoization to the EvmHookReader to avoid repeating configuration derivation + +### Patch Changes + +- f1712deb7: Fix objMerge implementation + ## 5.5.0 ### Minor Changes diff --git a/typescript/utils/package.json b/typescript/utils/package.json index 83c8ed9c3..9baa234bf 100644 --- a/typescript/utils/package.json +++ b/typescript/utils/package.json @@ -1,7 +1,7 @@ { "name": "@hyperlane-xyz/utils", "description": "General utilities and types for the Hyperlane network", - "version": "5.5.0", + "version": "5.6.0", "dependencies": { "@cosmjs/encoding": "^0.32.4", "@solana/web3.js": "^1.78.0", diff --git a/typescript/widgets/CHANGELOG.md b/typescript/widgets/CHANGELOG.md index 8e5869427..e4698dd65 100644 --- a/typescript/widgets/CHANGELOG.md +++ b/typescript/widgets/CHANGELOG.md @@ -1,5 +1,25 @@ # @hyperlane-xyz/widgets +## 5.6.0 + +### Patch Changes + +- e89f9e35d: Update registry to v4.7.0 +- Updated dependencies [f1712deb7] +- Updated dependencies [46044a2e9] +- Updated dependencies [02a5b92ba] +- Updated dependencies [29341950e] +- Updated dependencies [8001bbbd6] +- Updated dependencies [32d0a67c2] +- Updated dependencies [b1ff48bd1] +- Updated dependencies [d41aa6928] +- Updated dependencies [c3e9268f1] +- Updated dependencies [7d7bcc1a3] +- Updated dependencies [7f3e0669d] +- Updated dependencies [2317eca3c] + - @hyperlane-xyz/utils@5.6.0 + - @hyperlane-xyz/sdk@5.6.0 + ## 5.5.0 ### Minor Changes diff --git a/typescript/widgets/package.json b/typescript/widgets/package.json index 2e0177246..031a87479 100644 --- a/typescript/widgets/package.json +++ b/typescript/widgets/package.json @@ -1,15 +1,15 @@ { "name": "@hyperlane-xyz/widgets", "description": "Common react components for Hyperlane projects", - "version": "5.5.0", + "version": "5.6.0", "peerDependencies": { "react": "^18", "react-dom": "^18" }, "dependencies": { "@headlessui/react": "^2.1.8", - "@hyperlane-xyz/sdk": "5.5.0", - "@hyperlane-xyz/utils": "5.5.0", + "@hyperlane-xyz/sdk": "5.6.0", + "@hyperlane-xyz/utils": "5.6.0", "clsx": "^2.1.1", "react-tooltip": "^5.28.0" }, diff --git a/yarn.lock b/yarn.lock index ebfca2e5c..556803a51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7824,8 +7824,8 @@ __metadata: "@ethersproject/abi": "npm:*" "@ethersproject/providers": "npm:*" "@hyperlane-xyz/registry": "npm:4.7.0" - "@hyperlane-xyz/sdk": "npm:5.5.0" - "@hyperlane-xyz/utils": "npm:5.5.0" + "@hyperlane-xyz/sdk": "npm:5.6.0" + "@hyperlane-xyz/utils": "npm:5.6.0" "@inquirer/prompts": "npm:^3.0.0" "@types/chai-as-promised": "npm:^8" "@types/mocha": "npm:^10.0.1" @@ -7858,13 +7858,13 @@ __metadata: languageName: unknown linkType: soft -"@hyperlane-xyz/core@npm:5.4.1, @hyperlane-xyz/core@workspace:solidity": +"@hyperlane-xyz/core@npm:5.5.0, @hyperlane-xyz/core@workspace:solidity": version: 0.0.0-use.local resolution: "@hyperlane-xyz/core@workspace:solidity" dependencies: "@arbitrum/nitro-contracts": "npm:^1.2.1" "@eth-optimism/contracts": "npm:^0.6.0" - "@hyperlane-xyz/utils": "npm:5.5.0" + "@hyperlane-xyz/utils": "npm:5.6.0" "@layerzerolabs/lz-evm-oapp-v2": "npm:2.0.2" "@layerzerolabs/solidity-examples": "npm:^1.1.0" "@nomiclabs/hardhat-ethers": "npm:^2.2.3" @@ -7915,13 +7915,13 @@ __metadata: languageName: unknown linkType: soft -"@hyperlane-xyz/helloworld@npm:5.5.0, @hyperlane-xyz/helloworld@workspace:typescript/helloworld": +"@hyperlane-xyz/helloworld@npm:5.6.0, @hyperlane-xyz/helloworld@workspace:typescript/helloworld": version: 0.0.0-use.local resolution: "@hyperlane-xyz/helloworld@workspace:typescript/helloworld" dependencies: - "@hyperlane-xyz/core": "npm:5.4.1" + "@hyperlane-xyz/core": "npm:5.5.0" "@hyperlane-xyz/registry": "npm:4.7.0" - "@hyperlane-xyz/sdk": "npm:5.5.0" + "@hyperlane-xyz/sdk": "npm:5.6.0" "@nomiclabs/hardhat-ethers": "npm:^2.2.3" "@nomiclabs/hardhat-waffle": "npm:^2.0.6" "@openzeppelin/contracts-upgradeable": "npm:^4.9.3" @@ -7968,10 +7968,10 @@ __metadata: "@ethersproject/hardware-wallets": "npm:^5.7.0" "@ethersproject/providers": "npm:^5.7.2" "@google-cloud/secret-manager": "npm:^5.5.0" - "@hyperlane-xyz/helloworld": "npm:5.5.0" + "@hyperlane-xyz/helloworld": "npm:5.6.0" "@hyperlane-xyz/registry": "npm:4.7.0" - "@hyperlane-xyz/sdk": "npm:5.5.0" - "@hyperlane-xyz/utils": "npm:5.5.0" + "@hyperlane-xyz/sdk": "npm:5.6.0" + "@hyperlane-xyz/utils": "npm:5.6.0" "@inquirer/prompts": "npm:^5.3.8" "@nomiclabs/hardhat-ethers": "npm:^2.2.3" "@nomiclabs/hardhat-etherscan": "npm:^3.0.3" @@ -8037,7 +8037,7 @@ __metadata: languageName: node linkType: hard -"@hyperlane-xyz/sdk@npm:5.5.0, @hyperlane-xyz/sdk@workspace:typescript/sdk": +"@hyperlane-xyz/sdk@npm:5.6.0, @hyperlane-xyz/sdk@workspace:typescript/sdk": version: 0.0.0-use.local resolution: "@hyperlane-xyz/sdk@workspace:typescript/sdk" dependencies: @@ -8045,8 +8045,8 @@ __metadata: "@aws-sdk/client-s3": "npm:^3.74.0" "@cosmjs/cosmwasm-stargate": "npm:^0.32.4" "@cosmjs/stargate": "npm:^0.32.4" - "@hyperlane-xyz/core": "npm:5.4.1" - "@hyperlane-xyz/utils": "npm:5.5.0" + "@hyperlane-xyz/core": "npm:5.5.0" + "@hyperlane-xyz/utils": "npm:5.6.0" "@nomiclabs/hardhat-ethers": "npm:^2.2.3" "@nomiclabs/hardhat-waffle": "npm:^2.0.6" "@safe-global/api-kit": "npm:1.3.0" @@ -8087,7 +8087,7 @@ __metadata: languageName: unknown linkType: soft -"@hyperlane-xyz/utils@npm:5.5.0, @hyperlane-xyz/utils@workspace:typescript/utils": +"@hyperlane-xyz/utils@npm:5.6.0, @hyperlane-xyz/utils@workspace:typescript/utils": version: 0.0.0-use.local resolution: "@hyperlane-xyz/utils@workspace:typescript/utils" dependencies: @@ -8113,8 +8113,8 @@ __metadata: dependencies: "@headlessui/react": "npm:^2.1.8" "@hyperlane-xyz/registry": "npm:4.7.0" - "@hyperlane-xyz/sdk": "npm:5.5.0" - "@hyperlane-xyz/utils": "npm:5.5.0" + "@hyperlane-xyz/sdk": "npm:5.6.0" + "@hyperlane-xyz/utils": "npm:5.6.0" "@storybook/addon-essentials": "npm:^7.6.14" "@storybook/addon-interactions": "npm:^7.6.14" "@storybook/addon-links": "npm:^7.6.14"