Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ BorshSchemaContainer {
"Sui",
"ForeignChain__Sui",
),
(
13,
"Avalanche",
"ForeignChain__Avalanche",
),
(
14,
"Adi",
"ForeignChain__Adi",
),
],
},
"ForeignChainRpcWhitelist": Struct {
Expand All @@ -114,12 +124,18 @@ BorshSchemaContainer {
"ForeignChain__Abstract": Struct {
fields: Empty,
},
"ForeignChain__Adi": Struct {
fields: Empty,
},
"ForeignChain__Aptos": Struct {
fields: Empty,
},
"ForeignChain__Arbitrum": Struct {
fields: Empty,
},
"ForeignChain__Avalanche": Struct {
fields: Empty,
},
"ForeignChain__Base": Struct {
fields: Empty,
},
Expand Down
16 changes: 16 additions & 0 deletions crates/contract/tests/sandbox/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,22 @@ pub fn polygon_evm_request() -> ForeignChainRpcRequest {
})
}

pub fn avalanche_evm_request() -> ForeignChainRpcRequest {
ForeignChainRpcRequest::Avalanche(EvmRpcRequest {
tx_id: EvmTxId([0xbb; 32]),
extractors: vec![EvmExtractor::BlockHash],
finality: EvmFinality::Finalized,
})
}

pub fn adi_evm_request() -> ForeignChainRpcRequest {
ForeignChainRpcRequest::Adi(EvmRpcRequest {
tx_id: EvmTxId([0xbb; 32]),
extractors: vec![EvmExtractor::BlockHash],
finality: EvmFinality::Finalized,
})
}

pub fn ton_request() -> ForeignChainRpcRequest {
ForeignChainRpcRequest::Ton(TonRpcRequest {
tx_id: TonTxId([0xbb; 32]),
Expand Down
11 changes: 9 additions & 2 deletions crates/contract/tests/sandbox/foreign_chain_request.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#![allow(non_snake_case)]

use crate::sandbox::common::{
SandboxTestSetup, abstract_evm_request, aptos_extracted_values, aptos_request,
arbitrum_evm_request, await_pending_foreign_tx_request_observed_on_contract, base_evm_request,
SandboxTestSetup, abstract_evm_request, adi_evm_request, aptos_extracted_values, aptos_request,
arbitrum_evm_request, avalanche_evm_request,
await_pending_foreign_tx_request_observed_on_contract, base_evm_request,
bitcoin_extracted_values, bitcoin_request, bnb_evm_request, bogus_ton_log_extracted_value,
ethereum_evm_request, evm_block_hash_extracted_values, hyper_evm_request, polygon_evm_request,
register_foreign_chain_configuration, sign_foreign_tx_response, starknet_extracted_values,
Expand Down Expand Up @@ -32,6 +33,8 @@ const SIGNATURE_TIMEOUT_BLOCKS: u64 = 200;
#[case::ton(ton_request(), bogus_ton_log_extracted_value())]
#[case::aptos(aptos_request(), aptos_extracted_values())]
#[case::sui(sui_request(), sui_extracted_values())]
#[case::avalanche(avalanche_evm_request(), evm_block_hash_extracted_values())]
#[case::adi(adi_evm_request(), evm_block_hash_extracted_values())]
#[tokio::test]
async fn verify_foreign_transaction__should_succeed(
#[case] rpc_request: ForeignChainRpcRequest,
Expand Down Expand Up @@ -321,6 +324,8 @@ async fn verify_foreign_transaction__should_succeed_when_response_matches_expect
#[case::ton(ton_request())]
#[case::aptos(aptos_request())]
#[case::sui(sui_request())]
#[case::avalanche(avalanche_evm_request())]
#[case::adi(adi_evm_request())]
#[tokio::test]
async fn verify_foreign_transaction__should_reject_without_policy(
#[case] rpc_request: ForeignChainRpcRequest,
Expand Down Expand Up @@ -365,6 +370,8 @@ async fn verify_foreign_transaction__should_reject_without_policy(
#[case::ton(ton_request())]
#[case::aptos(aptos_request())]
#[case::sui(sui_request())]
#[case::avalanche(avalanche_evm_request())]
#[case::adi(adi_evm_request())]
#[tokio::test]
async fn verify_foreign_transaction__should_timeout_without_response(
#[case] rpc_request: ForeignChainRpcRequest,
Expand Down
60 changes: 59 additions & 1 deletion crates/contract/tests/snapshots/abi__abi_has_not_changed.snap
Original file line number Diff line number Diff line change
Expand Up @@ -256,19 +256,35 @@ expression: abi
12,
"Sui",
"ForeignChain__Sui"
],
[
13,
"Avalanche",
"ForeignChain__Avalanche"
],
[
14,
"Adi",
"ForeignChain__Adi"
]
]
}
},
"ForeignChain__Abstract": {
"Struct": null
},
"ForeignChain__Adi": {
"Struct": null
},
"ForeignChain__Aptos": {
"Struct": null
},
"ForeignChain__Arbitrum": {
"Struct": null
},
"ForeignChain__Avalanche": {
"Struct": null
},
"ForeignChain__Base": {
"Struct": null
},
Expand Down Expand Up @@ -3089,19 +3105,35 @@ expression: abi
12,
"Sui",
"ForeignChain__Sui"
],
[
13,
"Avalanche",
"ForeignChain__Avalanche"
],
[
14,
"Adi",
"ForeignChain__Adi"
]
]
}
},
"ForeignChain__Abstract": {
"Struct": null
},
"ForeignChain__Adi": {
"Struct": null
},
"ForeignChain__Aptos": {
"Struct": null
},
"ForeignChain__Arbitrum": {
"Struct": null
},
"ForeignChain__Avalanche": {
"Struct": null
},
"ForeignChain__Base": {
"Struct": null
},
Expand Down Expand Up @@ -4067,7 +4099,9 @@ expression: abi
"HyperEvm",
"Ton",
"Aptos",
"Sui"
"Sui",
"Avalanche",
"Adi"
]
},
"ForeignChainConfiguration": {
Expand Down Expand Up @@ -4234,6 +4268,30 @@ expression: abi
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"Avalanche"
],
"properties": {
"Avalanche": {
"$ref": "#/definitions/EvmRpcRequest"
}
},
"additionalProperties": false
},
{
"type": "object",
"required": [
"Adi"
],
"properties": {
"Adi": {
"$ref": "#/definitions/EvmRpcRequest"
}
},
"additionalProperties": false
}
]
},
Expand Down
58 changes: 57 additions & 1 deletion crates/e2e-tests/tests/foreign_chain_tx_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ struct MockServerUrls {
base: String,
arbitrum: String,
hyper_evm: String,
avalanche: String,
adi: String,
polygon: Vec<String>,
}

Expand Down Expand Up @@ -114,6 +116,8 @@ fn build_foreign_chains_config(urls: &MockServerUrls) -> ForeignChainsConfig {
)),
arbitrum: Some(mock_chain(&urls.arbitrum, Default::default())),
hyper_evm: Some(mock_chain(&urls.hyper_evm, Default::default())),
avalanche: Some(mock_chain(&urls.avalanche, Default::default())),
adi: Some(mock_chain(&urls.adi, Default::default())),
polygon: Some(mock_chain_with_providers(
common::build_providers_from_urls(&urls.polygon, "polygon"),
)),
Expand All @@ -129,6 +133,8 @@ async fn setup_foreign_tx_cluster() -> anyhow::Result<ForeignTxTestEnv> {
let base_server = MockServer::start();
let arbitrum_server = MockServer::start();
let hyper_evm_server = MockServer::start();
let avalanche_server = MockServer::start();
let adi_server = MockServer::start();

let bitcoin_mock_id = setup_bitcoin_mock(
&bitcoin_server,
Expand All @@ -154,6 +160,8 @@ async fn setup_foreign_tx_cluster() -> anyhow::Result<ForeignTxTestEnv> {
setup_starknet_mock(&starknet_server, MockAuthExpectation::None);
setup_evm_mock(&arbitrum_server, MockAuthExpectation::None);
setup_evm_mock(&hyper_evm_server, MockAuthExpectation::None);
setup_evm_mock(&avalanche_server, MockAuthExpectation::None);
setup_evm_mock(&adi_server, MockAuthExpectation::None);

// Polygon is configured with three RPC providers so the test can assert
// that `FanOut` queries every one of them.
Expand All @@ -175,6 +183,8 @@ async fn setup_foreign_tx_cluster() -> anyhow::Result<ForeignTxTestEnv> {
base: base_server.url("/"),
arbitrum: arbitrum_server.url("/"),
hyper_evm: hyper_evm_server.url("/"),
avalanche: avalanche_server.url("/"),
adi: adi_server.url("/"),
polygon: polygon_mocks.iter().map(|m| m.server.url("/")).collect(),
};

Expand All @@ -186,6 +196,8 @@ async fn setup_foreign_tx_cluster() -> anyhow::Result<ForeignTxTestEnv> {
starknet_server,
arbitrum_server,
hyper_evm_server,
avalanche_server,
adi_server,
];

let fc_config = build_foreign_chains_config(&urls);
Expand All @@ -198,6 +210,8 @@ async fn setup_foreign_tx_cluster() -> anyhow::Result<ForeignTxTestEnv> {
ForeignChain::Base,
ForeignChain::Arbitrum,
ForeignChain::HyperEvm,
ForeignChain::Avalanche,
ForeignChain::Adi,
ForeignChain::Polygon,
]
.into_iter()
Expand Down Expand Up @@ -487,6 +501,44 @@ async fn verify_hyper_evm(env: &ForeignTxTestEnv) -> anyhow::Result<()> {
verify_foreign_tx_response(&outcome)
}

async fn verify_avalanche(env: &ForeignTxTestEnv) -> anyhow::Result<()> {
let request = VerifyForeignTransactionRequestArgs {
request: ForeignChainRpcRequest::Avalanche(EvmRpcRequest {
tx_id: EvmTxId([0xbb; 32]),
extractors: vec![EvmExtractor::BlockHash, EvmExtractor::Log { log_index: 0 }],
finality: EvmFinality::Finalized,
}),
domain_id: env.foreign_tx_domain_id,
payload_version: ForeignTxPayloadVersion::V1,
expected_payload_hash: None,
};
let outcome = env
.cluster
.send_verify_foreign_transaction(&request)
.await
.context("verify_foreign_transaction (Avalanche) failed")?;
verify_foreign_tx_response(&outcome)
}

async fn verify_adi(env: &ForeignTxTestEnv) -> anyhow::Result<()> {
let request = VerifyForeignTransactionRequestArgs {
request: ForeignChainRpcRequest::Adi(EvmRpcRequest {
tx_id: EvmTxId([0xbb; 32]),
extractors: vec![EvmExtractor::BlockHash, EvmExtractor::Log { log_index: 0 }],
finality: EvmFinality::Finalized,
}),
domain_id: env.foreign_tx_domain_id,
payload_version: ForeignTxPayloadVersion::V1,
expected_payload_hash: None,
};
let outcome = env
.cluster
.send_verify_foreign_transaction(&request)
.await
.context("verify_foreign_transaction (ADI) failed")?;
verify_foreign_tx_response(&outcome)
}

/// A successful verification implies the credentialed mock answered,
/// so this is a backstop against the mock setup being loosened to answer unauthenticated requests.
fn assert_authenticated_provider_was_queried(mock: &MockServerExt, provider: &str) {
Expand Down Expand Up @@ -541,7 +593,7 @@ async fn verify_polygon(env: &ForeignTxTestEnv) -> anyhow::Result<()> {
#[expect(non_snake_case)]
async fn verify_foreign_transaction__should_sign_all_supported_chains() {
// Given — 2-node cluster with Bitcoin, Abstract, BNB, Base, Starknet,
// Arbitrum, HyperEVM, and Polygon configured
// Arbitrum, HyperEVM, Avalanche, ADI, and Polygon configured
let env = setup_foreign_tx_cluster()
.await
.expect("setup_foreign_tx_cluster failed");
Expand Down Expand Up @@ -570,6 +622,10 @@ async fn verify_foreign_transaction__should_sign_all_supported_chains() {
verify_hyper_evm(&env)
.await
.expect("hyper_evm verification failed");
verify_avalanche(&env)
.await
.expect("avalanche verification failed");
verify_adi(&env).await.expect("adi verification failed");
verify_polygon(&env)
.await
.expect("polygon verification failed");
Expand Down
14 changes: 14 additions & 0 deletions crates/foreign-chain-health-check/src/golden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub struct GoldenSet {
pub arbitrum: Option<BlockHashVector>,
pub polygon: Option<BlockHashVector>,
pub hyper_evm: Option<BlockHashVector>,
pub avalanche: Option<BlockHashVector>,
pub adi: Option<BlockHashVector>,
pub abstract_chain: Option<BlockHashVector>,
pub bitcoin: Option<BlockHashVector>,
pub starknet: Option<BlockHashVector>,
Expand Down Expand Up @@ -72,6 +74,14 @@ const MAINNET: GoldenSet = GoldenSet {
tx: "4d94e2c9c33c533f125bd28a788e80ee24c108356e8fa8a7878f642cf94dcf4a",
block_hash: "657b2ee81add87e3f654840425baca06a06d5876f6d2d873197e70f00f6762e6",
}),
avalanche: Some(BlockHashVector {
tx: "51f5b652c9917189b64a5abb5e1814d3bd0a58dbe433f3f7a58e9b0d20f40bb5",
block_hash: "ce5c4ceb1b1c14ba8a0d58f23545106934278390446466810991245a9cff2a43",
}),
adi: Some(BlockHashVector {
tx: "df89849ce8e1b4cf390560395198a10f1bd0498822c6880346a8ce28869ec8e5",
block_hash: "e49e64cb14a417a1356929043dc87559c57afb540492bc62c8c0d8270902f5c2",
}),
abstract_chain: Some(BlockHashVector {
tx: "4572b72d765f07712cf571993fd805888ede9cd05107f65338defee02f7ea755",
block_hash: "3bb255d468a552a75fc3f4916623b207ceb2d3074dfa14442ac03f0f73423708",
Expand Down Expand Up @@ -100,6 +110,8 @@ const TESTNET: GoldenSet = GoldenSet {
arbitrum: None,
polygon: None,
hyper_evm: None,
avalanche: None,
adi: None,
abstract_chain: Some(BlockHashVector {
tx: "497fc5f5b5d81d6bc15cccc6d4d8be8ef6ad19376233b944a60dc435593f7234",
block_hash: "4c93dd4a8f347e6480b0a44f8c2b7eecdfb31d711e8d542fd60112ea5d98fb02",
Expand Down Expand Up @@ -196,6 +208,8 @@ mod tests {
set.arbitrum,
set.polygon,
set.hyper_evm,
set.avalanche,
set.adi,
set.abstract_chain,
set.bitcoin,
]
Expand Down
Loading