feat: initialize Kurdistan SDK - independent fork of Polkadot SDK

This commit is contained in:
2025-12-13 15:44:15 +03:00
commit e4778b4576
6838 changed files with 1847450 additions and 0 deletions
@@ -0,0 +1,97 @@
[package]
name = "snowbridge-pallet-inbound-queue"
description = "Snowbridge Inbound Queue Pallet"
version = "0.2.0"
authors = ["Snowfork <contact@snowfork.com>"]
edition.workspace = true
repository.workspace = true
license = "Apache-2.0"
categories = ["cryptography::cryptocurrencies"]
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[package.metadata.pezkuwi-sdk]
exclude-from-umbrella = true
[dependencies]
alloy-core = { workspace = true, features = ["sol-types"] }
codec = { features = ["derive"], workspace = true }
scale-info = { features = ["derive"], workspace = true }
serde = { optional = true, workspace = true, default-features = true }
tracing = { workspace = true }
frame-benchmarking = { optional = true, workspace = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-balances = { workspace = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
xcm = { workspace = true }
xcm-executor = { workspace = true }
snowbridge-beacon-primitives = { workspace = true }
snowbridge-core = { workspace = true }
snowbridge-inbound-queue-primitives = { workspace = true }
snowbridge-pallet-inbound-queue-fixtures = { optional = true, workspace = true }
[dev-dependencies]
frame-benchmarking = { workspace = true, default-features = true }
hex-literal = { workspace = true, default-features = true }
snowbridge-pallet-ethereum-client = { workspace = true, default-features = true }
sp-keyring = { workspace = true, default-features = true }
[features]
default = ["std"]
std = [
"alloy-core/std",
"codec/std",
"frame-benchmarking/std",
"frame-support/std",
"frame-system/std",
"pallet-balances/std",
"scale-info/std",
"serde",
"snowbridge-beacon-primitives/std",
"snowbridge-core/std",
"snowbridge-inbound-queue-primitives/std",
"snowbridge-pallet-inbound-queue-fixtures?/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
"tracing/std",
"xcm-executor/std",
"xcm/std",
]
runtime-benchmarks = [
"frame-benchmarking",
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"snowbridge-beacon-primitives/runtime-benchmarks",
"snowbridge-core/runtime-benchmarks",
"snowbridge-inbound-queue-primitives/runtime-benchmarks",
"snowbridge-pallet-ethereum-client/runtime-benchmarks",
"snowbridge-pallet-inbound-queue-fixtures/runtime-benchmarks",
"sp-io/runtime-benchmarks",
"sp-keyring/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"xcm-executor/runtime-benchmarks",
"xcm/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-balances/try-runtime",
"snowbridge-inbound-queue-primitives/try-runtime",
"snowbridge-pallet-ethereum-client/try-runtime",
"sp-runtime/try-runtime",
]
@@ -0,0 +1,3 @@
# Ethereum Inbound Queue
Reads messages from Ethereum and sends it to intended destination on PezkuwiChain, using XCM.
@@ -0,0 +1,41 @@
[package]
name = "snowbridge-pallet-inbound-queue-fixtures"
description = "Snowbridge Inbound Queue Test Fixtures"
version = "0.10.0"
authors = ["Snowfork <contact@snowfork.com>"]
edition.workspace = true
repository.workspace = true
license = "Apache-2.0"
categories = ["cryptography::cryptocurrencies"]
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[package.metadata.pezkuwi-sdk]
exclude-from-umbrella = true
[dependencies]
hex-literal = { workspace = true, default-features = true }
snowbridge-beacon-primitives = { workspace = true }
snowbridge-core = { workspace = true }
snowbridge-inbound-queue-primitives = { workspace = true }
sp-core = { workspace = true }
sp-std = { workspace = true }
[features]
default = ["std"]
std = [
"snowbridge-beacon-primitives/std",
"snowbridge-core/std",
"snowbridge-inbound-queue-primitives/std",
"sp-core/std",
"sp-std/std",
]
runtime-benchmarks = [
"snowbridge-beacon-primitives/runtime-benchmarks",
"snowbridge-core/runtime-benchmarks",
"snowbridge-inbound-queue-primitives/runtime-benchmarks",
]
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
#![cfg_attr(not(feature = "std"), no_std)]
pub mod register_token;
pub mod send_native_eth;
pub mod send_token;
pub mod send_token_to_penpal;
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
// Generated, do not edit!
// See ethereum client README.md for instructions to generate
use hex_literal::hex;
use snowbridge_beacon_primitives::{
types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader,
};
use snowbridge_inbound_queue_primitives::{EventFixture, EventProof, Log, Proof};
use sp_core::U256;
use sp_std::vec;
pub fn make_register_token_message() -> EventFixture {
EventFixture {
event: EventProof {
event_log: Log {
address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(),
topics: vec![
hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(),
hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(),
hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(),
],
data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(),
},
proof: Proof {
receipt_proof: (vec![
hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").to_vec(),
hex!("4a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f").to_vec(),
], vec![
hex!("f851a09c01dd6d2d8de951c45af23d3ad00829ce021c04d6c8acbe1612d456ee320d4980808080808080a04a98e45a319168b0fc6005ce6b744ee9bf54338e2c0784b976a8578d241ced0f8080808080808080").to_vec(),
hex!("f9028c30b9028802f90284018301d205b9010000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000000000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000040004000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000200000000000010f90179f85894eda338e4dc46038493b885327842fd3e301cab39e1a0f78bb28d4b1d7da699e5c0bc2be29c2b04b5aab6aacf6298fe5304f9db9c6d7ea000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7df9011c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e00a736aa00000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").to_vec(),
]),
execution_proof: ExecutionProof {
header: BeaconHeader {
slot: 393,
proposer_index: 4,
parent_root: hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(),
state_root: hex!("b62ac34a8cb82497be9542fe2114410c9f6021855b766015406101a1f3d86434").into(),
body_root: hex!("04005fe231e11a5b7b1580cb73b177ae8b338bedd745497e6bb7122126a806db").into(),
},
ancestry_proof: Some(AncestryProof {
header_branch: vec![
hex!("6545b47a614a1dd4cad042a0cdbbf5be347e8ffcdc02c6c64540d5153acebeef").into(),
hex!("fa84cc88ca53a72181599ff4eb07d8b444bce023fe2347c3b4f51004c43439d3").into(),
hex!("cadc8ae211c6f2221c9138e829249adf902419c78eb4727a150baa4d9a02cc9d").into(),
hex!("33a89962df08a35c52bd7e1d887cd71fa7803e68787d05c714036f6edf75947c").into(),
hex!("2c9760fce5c2829ef3f25595a703c21eb22d0186ce223295556ed5da663a82cf").into(),
hex!("e1aa87654db79c8a0ecd6c89726bb662fcb1684badaef5cd5256f479e3c622e1").into(),
hex!("aa70d5f314e4a1fbb9c362f3db79b21bf68b328887248651fbd29fc501d0ca97").into(),
hex!("160b6c235b3a1ed4ef5f80b03ee1c76f7bf3f591c92fca9d8663e9221b9f9f0f").into(),
hex!("f68d7dcd6a07a18e9de7b5d2aa1980eb962e11d7dcb584c96e81a7635c8d2535").into(),
hex!("1d5f912dfd6697110dd1ecb5cb8e77952eef57d85deb373572572df62bb157fc").into(),
hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(),
hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(),
hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(),
],
finalized_block_root: hex!("751414cd97c0624f922b3e80285e9f776b08fa22fd5f87391f2ed7ef571a8d46").into(),
}),
execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader {
parent_hash: hex!("8092290aa21b7751576440f77edd02a94058429ce50e63a92d620951fb25eda2").into(),
fee_recipient: hex!("0000000000000000000000000000000000000000").into(),
state_root: hex!("96a83e9ddf745346fafcb0b03d57314623df669ed543c110662b21302a0fae8b").into(),
receipts_root: hex!("dccdfceea05036f7b61dcdabadc937945d31e68a8d3dfd4dc85684457988c284").into(),
logs_bloom: hex!("00000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000080000000400000000000000000000004000000000080000000000000000000000000000000000010100000000000000000000000000000000020000000000000000000000000000000000080000000000000000000000000000040004000000000000002002002000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000080000000000000000000000000000000000100000000000000000200000200000010").into(),
prev_randao: hex!("62e309d4f5119d1f5c783abc20fc1a549efbab546d8d0b25ff1cfd58be524e67").into(),
block_number: 393,
gas_limit: 54492273,
gas_used: 199644,
timestamp: 1710552813,
extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(),
base_fee_per_gas: U256::from(7u64),
block_hash: hex!("6a9810efb9581d30c1a5c9074f27c68ea779a8c1ae31c213241df16225f4e131").into(),
transactions_root: hex!("2cfa6ed7327e8807c7973516c5c32a68ef2459e586e8067e113d081c3bd8c07d").into(),
withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(),
blob_gas_used: 0,
excess_blob_gas: 0,
}),
execution_branch: vec![
hex!("a6833fa629f3286b6916c6e50b8bf089fc9126bee6f64d0413b4e59c1265834d").into(),
hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(),
hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(),
hex!("d3af7c05c516726be7505239e0b9c7cb53d24abce6b91cdb3b3995f0164a75da").into(),
],
}
},
},
finalized_header: BeaconHeader {
slot: 864,
proposer_index: 4,
parent_root: hex!("614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614").into(),
state_root: hex!("5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a").into(),
body_root: hex!("0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e").into(),
},
block_roots_root: hex!("b9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10").into(),
}
}
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
// Generated, do not edit!
// See ethereum client README.md for instructions to generate
use hex_literal::hex;
use snowbridge_beacon_primitives::{
types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader,
};
use snowbridge_inbound_queue_primitives::{EventFixture, EventProof, Log, Proof};
use sp_core::U256;
use sp_std::vec;
pub fn make_send_native_eth_message() -> EventFixture {
EventFixture {
event: EventProof {
event_log: Log {
address: hex!("87d1f7fdfee7f651fabc8bfcb6e086c278b77a7d").into(),
topics: vec![
hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(),
hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(),
hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(),
],
data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa0000000000010000000000000000000000000000000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e8764817000000000000000000000000").into(),
},
proof: Proof {
receipt_proof: (vec![
hex!("17cd4d05dde30703008a4f213205923630cff8e6bc9d5d95a52716bfb5551fd7").to_vec(),
], vec![
hex!("f903b4822080b903ae02f903aa018301a7fcb9010000000000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000000000000000000000000000000000000000000000000000001080000000000000000000000000000000000000000080000000000020000000000000000000800010100000000000000000000000000000000000200000000000000000000000000001000000040080008000000000000000000040000000021000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000200000000000000f9029ff9015d9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000000000000000000000000000000000000000003e8b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000208eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48f9013c9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa0000000000010000000000000000000000000000000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e8764817000000000000000000000000").to_vec(),
]),
execution_proof: ExecutionProof {
header: BeaconHeader {
slot: 246,
proposer_index: 7,
parent_root: hex!("4faaac5d2fa0b8884fe1175c7cac1c92aac9eba5a20b4302edb98a56428c5974").into(),
state_root: hex!("882c13f1d56df781e3444a78cae565bfa1c89822c86cdb0daea71f5351231580").into(),
body_root: hex!("c47eb72204b1ca567396dacef8b0214027eb7f0789330b55166085d1f9cb4c65").into(),
},
ancestry_proof: Some(AncestryProof {
header_branch: vec![
hex!("38e2454bc93c4cfafcea772b8531e4802bbd2561366620699096dd4e591bc488").into(),
hex!("3d7389fb144ccaeca8b8e1667ce1d1538dfceb50bf1e49c4b368a223f051fda3").into(),
hex!("0d49c9c24137ad4d86ebca2f36a159573a68b5d5d60e317776c77cc8b6093034").into(),
hex!("0fadc6735bcdc2793a5039a806fbf39984c39374ed4d272c1147e1c23df88983").into(),
hex!("3a058ad4b169eebb4c754c8488d41e56a7a0e5f8b55b5ec67452a8d326585c69").into(),
hex!("de200426caa9bc03f8e0033b4ef4df1db6501924b5c10fb7867e76db942b903c").into(),
hex!("48b578632bc40eebb517501f179ffdd06d762c03e9383df16fc651eeddd18806").into(),
hex!("98d9d6904b2a6a285db4c4ae59a07100cd38ec4d9fb7a16a10fe83ec99e6ba1d").into(),
hex!("1b2bbae6e684864b714654a60778664e63ba6c3c9bed8074ec1a0380fe5042e6").into(),
hex!("eb907a888eadf5a7e2bd0a3a5a9369e409c7aa688bd4cde758d5b608c6c82785").into(),
hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(),
hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(),
hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(),
],
finalized_block_root: hex!("440615588532ce496a93d189cb0ef1df7cf67d529faee0fd03213ce26ea115e5").into(),
}),
execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader {
parent_hash: hex!("a8c89213b7d7d2ac76462d89e6a7384374db905b657ad803d3c86f88f86c39df").into(),
fee_recipient: hex!("0000000000000000000000000000000000000000").into(),
state_root: hex!("a1e8175213a6a43da17fae65109245867cbc60e3ada16b8ac28c6b208761c772").into(),
receipts_root: hex!("17cd4d05dde30703008a4f213205923630cff8e6bc9d5d95a52716bfb5551fd7").into(),
logs_bloom: hex!("00000000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000000000000000000000000000000000000000000000000000001080000000000000000000000000000000000000000080000000000020000000000000000000800010100000000000000000000000000000000000200000000000000000000000000001000000040080008000000000000000000040000000021000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000200000000000000").into(),
prev_randao: hex!("b9b26dc14ea8c57d069fde0c94ad31c2558365c3986a0c06558470f8c02e62ce").into(),
block_number: 246,
gas_limit: 62908420,
gas_used: 108540,
timestamp: 1734718384,
extra_data: hex!("d983010e08846765746888676f312e32322e358664617277696e").into(),
base_fee_per_gas: U256::from(7u64),
block_hash: hex!("878195e2ea83c74d475363d03d41a7fbfc4026d6e5bcffb713928253984a64a7").into(),
transactions_root: hex!("909139b3137666b4551b629ce6d9fb7e5e6f6def8a48d078448ec6600fe63c7f").into(),
withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(),
blob_gas_used: 0,
excess_blob_gas: 0,
}),
execution_branch: vec![
hex!("5d78e26ea639df17c2194ff925f782b9522009d58cfc60e3d34ba79a19f8faf1").into(),
hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(),
hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(),
hex!("3d84b2809a36450186e5169995a5e3cab55d751aee90fd8456b33d871ccaa463").into(),
],
}
},
},
finalized_header: BeaconHeader {
slot: 608,
proposer_index: 3,
parent_root: hex!("f10c2349530dbd339a72886270e2e304bb68155af68c918c850acd9ab341350f").into(),
state_root: hex!("6df0ef4cbb4986a84ff0763727402b88636e6b5535022cd3ad6967b8dd799402").into(),
body_root: hex!("f66fc1c022f07f91c777ad5c464625fc0b43d3e7a45650567dce60011210f574").into(),
},
block_roots_root: hex!("1c0dbf54db070770f5e573b72afe0aac2b0e3cf312107d1cd73bf64d7a2ed90c").into(),
}
}
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
// Generated, do not edit!
// See ethereum client README.md for instructions to generate
use hex_literal::hex;
use snowbridge_beacon_primitives::{
types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader,
};
use snowbridge_inbound_queue_primitives::{EventFixture, EventProof, Log, Proof};
use sp_core::U256;
use sp_std::vec;
pub fn make_send_token_message() -> EventFixture {
EventFixture {
event: EventProof {
event_log: Log {
address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(),
topics: vec![
hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(),
hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(),
hex!("c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26f").into(),
],
data: hex!("00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000").into(),
},
proof: Proof {
receipt_proof: (vec![
hex!("f9d844c5b79638609ba385b910fec3b5d891c9d7b189f135f0432f33473de915").to_vec(),
], vec![
hex!("f90451822080b9044b02f90447018301bcb6b9010000800000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020200000000000000000000000000003000000040080008000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200800000000000f9033cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000000000000000000000000000000000000000003e8b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000208eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48f9013c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0c8eaf22f2cb07bac4679df0a660e7115ed87fcfd4e32ac269f6540265bbbd26fb8c000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000").to_vec(),
]),
execution_proof: ExecutionProof {
header: BeaconHeader {
slot: 2321,
proposer_index: 5,
parent_root: hex!("2add14727840d3a5ea061e14baa47030bb81380a65999200d119e73b86411d20").into(),
state_root: hex!("d962981467920bb2b7efa4a7a1baf64745582c3250857f49a957c5dae9a0da39").into(),
body_root: hex!("18e3f7f51a350f371ad35d166f2683b42af51d1836b295e4093be08acb0dcb7a").into(),
},
ancestry_proof: Some(AncestryProof {
header_branch: vec![
hex!("2add14727840d3a5ea061e14baa47030bb81380a65999200d119e73b86411d20").into(),
hex!("48b2e2f5256906a564e5058698f70e3406765fefd6a2edc064bb5fb88aa2ed0a").into(),
hex!("e5ed7c704e845418219b2fda42cd2f3438ffbe4c4b320935ae49439c6189f7a7").into(),
hex!("4a7ce24526b3f571548ad69679e4e260653a1b3b911a344e7f988f25a5c917a7").into(),
hex!("46fc859727ab0d0e8c344011f7d7a4426ccb537bb51363397e56cc7153f56391").into(),
hex!("f496b6f85a7c6c28a9048f2153550a7c5bcb4b23844ed3b87f6baa646124d8a3").into(),
hex!("7318644e474beb46e595a1875acc7444b937f5208065241911d2a71ac50c2de3").into(),
hex!("5cf48519e518ac64286aef5391319782dd38831d5dcc960578a6b9746d5f8cee").into(),
hex!("efb3e50fa39ca9fe7f76adbfa36fa8451ec2fd5d07b22aaf822137c04cf95a76").into(),
hex!("2206cd50750355ffaef4a67634c21168f2b564c58ffd04f33b0dc7af7dab3291").into(),
hex!("1a4014f6c4fcce9949fba74cb0f9e88df086706f9e05560cc9f0926f8c90e373").into(),
hex!("2df7cc0bcf3060be4132c63da7599c2600d9bbadf37ab001f15629bc2255698e").into(),
hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(),
],
finalized_block_root: hex!("f869dd1c9598043008a3ac2a5d91b3d6c7b0bb3295b3843bc84c083d70b0e604").into(),
}),
execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader {
parent_hash: hex!("5d7859883dde1eba6c98b20eac18426134b25da2a89e5e360f3343b15e0e0a31").into(),
fee_recipient: hex!("0000000000000000000000000000000000000000").into(),
state_root: hex!("f8fbebed4c84d46231bd293bb9fbc9340d5c28c284d99fdaddb77238b8960ae2").into(),
receipts_root: hex!("f9d844c5b79638609ba385b910fec3b5d891c9d7b189f135f0432f33473de915").into(),
logs_bloom: hex!("00800000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000010000000000000000000000008000000200000000000000001000008000000000000000000000000000000008000080000000000200000000000000000000000000100000000000000000011000000000000020200000000000000000000000000003000000040080008000000000000000000040044000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200800000000000").into(),
prev_randao: hex!("15533eeb366c6386bea5aeb8f425871928348c092209e4377f2418a6dedd7fd0").into(),
block_number: 2321,
gas_limit: 30000000,
gas_used: 113846,
timestamp: 1710554741,
extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(),
base_fee_per_gas: U256::from(7u64),
block_hash: hex!("585a07122a30339b03b6481eae67c2d3de2b6b64f9f426230986519bf0f1bdfe").into(),
transactions_root: hex!("09cd60ee2207d804397c81f7b7e1e5d3307712b136e5376623a80317a4bdcd7a").into(),
withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(),
blob_gas_used: 0,
excess_blob_gas: 0,
}),
execution_branch: vec![
hex!("9d419471a9a4719b40e7607781fbe32d9a7766b79805505c78c0c58133496ba2").into(),
hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(),
hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(),
hex!("bee375b8f1bbe4cd0e783c78026c1829ae72741c2dead5cab05d6834c5e5df65").into(),
],
}
},
},
finalized_header: BeaconHeader {
slot: 4032,
proposer_index: 5,
parent_root: hex!("180aaaec59d38c3860e8af203f01f41c9bc41665f4d17916567c80f6cd23e8a2").into(),
state_root: hex!("3341790429ed3bf894cafa3004351d0b99e08baf6c38eb2a54d58e69fd2d19c6").into(),
body_root: hex!("a221e0c695ac7b7d04ce39b28b954d8a682ecd57961d81b44783527c6295f455").into(),
},
block_roots_root: hex!("5744385ef06f82e67606f49aa29cd162f2e837a68fb7bd82f1fc6155d9f8640f").into(),
}
}
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
// Generated, do not edit!
// See ethereum client README.md for instructions to generate
use hex_literal::hex;
use snowbridge_beacon_primitives::{
types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader,
};
use snowbridge_inbound_queue_primitives::{EventFixture, EventProof, Log, Proof};
use sp_core::U256;
use sp_std::vec;
pub fn make_send_token_to_penpal_message() -> EventFixture {
EventFixture {
event: EventProof {
event_log: Log {
address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(),
topics: vec![
hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(),
hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(),
hex!("be323bced46a1a49c8da2ab62ad5e974fd50f1dabaeed70b23ca5bcf14bfe4aa").into(),
],
data: hex!("00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").into(),
},
proof: Proof {
receipt_proof: (vec![
hex!("106f1eaeac04e469da0020ad5c8a72af66323638bd3f561a3c8236063202c120").to_vec(),
], vec![
hex!("f90471822080b9046b02f904670183017d9cb9010000800000000000008000000000000000000000000000004000000000000000000400000000004000000000001000000010000000000000000000001008000000000000000000000001000008000040000000000000000000000000008000080000000000200000000000000000000000000100000000000000000010000000000000020000000000000000000000000000003000000000080018000000000000000000040004000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200820000000000f9035cf89b9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000057a2d4ff0c3866d96556884bf09fecdd7ccd530ca00000000000000000000000000000000000000000000000000de0b6b3a7640000f9015d94eda338e4dc46038493b885327842fd3e301cab39f884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a000000000000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7da000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000000000000000000000000000000000000000007d0b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000201cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07cf9015c94eda338e4dc46038493b885327842fd3e301cab39f863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a0be323bced46a1a49c8da2ab62ad5e974fd50f1dabaeed70b23ca5bcf14bfe4aab8e000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000007300a736aa00000000000187d1f7fdfee7f651fabc8bfcb6e086c278b77a7d01d00700001cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c00286bee000000000000000000000000000064a7b3b6e00d000000000000000000e40b5402000000000000000000000000000000000000000000000000").to_vec(),
]),
execution_proof: ExecutionProof {
header: BeaconHeader {
slot: 4235,
proposer_index: 4,
parent_root: hex!("1b31e6264c19bcad120e434e0aede892e7d7c8ed80ab505cb593d9a4a16bc566").into(),
state_root: hex!("725f51771a0ecf72c647a283ab814ca088f998eb8c203181496b0b8e01f624fa").into(),
body_root: hex!("6f1c326d192e7e97e21e27b16fd7f000b8fa09b435ff028849927e382302b0ce").into(),
},
ancestry_proof: Some(AncestryProof {
header_branch: vec![
hex!("1b31e6264c19bcad120e434e0aede892e7d7c8ed80ab505cb593d9a4a16bc566").into(),
hex!("335eb186c077fa7053ec96dcc5d34502c997713d2d5bc4eb74842118d8cd5a64").into(),
hex!("326607faf2a7dfc9cfc4b6895f8f3d92a659552deb2c8fd1e892ec00c86c734c").into(),
hex!("4e20002125d7b6504df7c774f3f48e018e1e6762d03489149670a8335bba1425").into(),
hex!("e76af5cd61aade5aec8282b6f1df9046efa756b0466bba5e49032410f7739a1b").into(),
hex!("ee4dcd9527712116380cddafd120484a3bedf867225bbb86850b84decf6da730").into(),
hex!("e4687a07421d3150439a2cd2f09f3b468145d75b359a2e5fa88dfbec51725b15").into(),
hex!("38eaa78978e95759aa9b6f8504a8dbe36151f20ae41907e6a1ea165700ceefcd").into(),
hex!("1c1b071ec6f13e15c47d07d1bfbcc9135d6a6c819e68e7e6078a2007418c1a23").into(),
hex!("0b3ad7ad193c691c8c4ba1606ad2a90482cd1d033c7db58cfe739d0e20431e9e").into(),
hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(),
hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(),
hex!("b2ffec5f2c14640305dd941330f09216c53b99d198e93735a400a6d3a4de191f").into(),
],
finalized_block_root: hex!("08be7a59e947f08cd95c4ef470758730bf9e3b0db0824cb663ea541c39b0e65c").into(),
}),
execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader {
parent_hash: hex!("5d1186ae041f58785edb2f01248e95832f2e5e5d6c4eb8f7ff2f58980bfc2de9").into(),
fee_recipient: hex!("0000000000000000000000000000000000000000").into(),
state_root: hex!("2a66114d20e93082c8e9b47c8d401a937013487d757c9c2f3123cf43dc1f656d").into(),
receipts_root: hex!("106f1eaeac04e469da0020ad5c8a72af66323638bd3f561a3c8236063202c120").into(),
logs_bloom: hex!("00800000000000008000000000000000000000000000004000000000000000000400000000004000000000001000000010000000000000000000001008000000000000000000000001000008000040000000000000000000000000008000080000000000200000000000000000000000000100000000000000000010000000000000020000000000000000000000000000003000000000080018000000000000000000040004000021000000002000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000200820000000000").into(),
prev_randao: hex!("92e063c7e369b74149fdd1d7132ed2f635a19b9d8bff57637b8ee4736576426e").into(),
block_number: 4235,
gas_limit: 30000000,
gas_used: 97692,
timestamp: 1710556655,
extra_data: hex!("d983010d0b846765746888676f312e32312e368664617277696e").into(),
base_fee_per_gas: U256::from(7u64),
block_hash: hex!("ce24fe3047aa20a8f222cd1d04567c12b39455400d681141962c2130e690953f").into(),
transactions_root: hex!("0c8388731de94771777c60d452077065354d90d6e5088db61fc6a134684195cc").into(),
withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(),
blob_gas_used: 0,
excess_blob_gas: 0,
}),
execution_branch: vec![
hex!("99d397fa180078e66cd3a3b77bcb07553052f4e21d447167f3a406f663b14e6a").into(),
hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(),
hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(),
hex!("53ddf17147819c1abb918178b0230d965d1bc2c0d389f45e91e54cb1d2d468aa").into(),
],
}
},
},
finalized_header: BeaconHeader {
slot: 4672,
proposer_index: 4,
parent_root: hex!("951233bf9f4bddfb2fa8f54e3bd0c7883779ef850e13e076baae3130dd7732db").into(),
state_root: hex!("4d303003b8cb097cbcc14b0f551ee70dac42de2c1cc2f4acfca7058ca9713291").into(),
body_root: hex!("664d13952b6f369bf4cf3af74d067ec33616eb57ed3a8a403fd5bae4fbf737dd").into(),
},
block_roots_root: hex!("af71048297c070e6539cf3b9b90ae07d86d363454606bc239734629e6b49b983").into(),
}
}
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use super::*;
use crate::Pallet as InboundQueue;
use frame_benchmarking::v2::*;
use frame_support::assert_ok;
use frame_system::RawOrigin;
#[benchmarks]
mod benchmarks {
use super::*;
#[benchmark]
fn submit() -> Result<(), BenchmarkError> {
let caller: T::AccountId = whitelisted_caller();
let create_message = T::Helper::initialize_storage();
let sovereign_account = sibling_sovereign_account::<T>(1000u32.into());
let minimum_balance = T::Token::minimum_balance();
// So that the receiving account exists
assert_ok!(T::Token::mint_into(&caller, minimum_balance));
// Fund the sovereign account (teyrchain sovereign account) so it can transfer a reward
// fee to the caller account
assert_ok!(T::Token::mint_into(
&sovereign_account,
3_000_000_000_000u128
.try_into()
.unwrap_or_else(|_| panic!("unable to cast sovereign account balance")),
));
#[block]
{
assert_ok!(InboundQueue::<T>::submit(
RawOrigin::Signed(caller.clone()).into(),
create_message.event,
));
}
Ok(())
}
impl_benchmark_test_suite!(InboundQueue, crate::mock::new_tester(), crate::mock::Test);
}
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use snowbridge_core::ChannelId;
use snowbridge_inbound_queue_primitives::Log;
use sp_core::{RuntimeDebug, H160, H256};
use sp_std::prelude::*;
use alloy_core::{primitives::B256, sol, sol_types::SolEvent};
sol! {
event OutboundMessageAccepted(bytes32 indexed channel_id, uint64 nonce, bytes32 indexed message_id, bytes payload);
}
/// An inbound message that has had its outer envelope decoded.
#[derive(Clone, RuntimeDebug)]
pub struct Envelope {
/// The address of the outbound queue on Ethereum that emitted this message as an event log
pub gateway: H160,
/// The message Channel
pub channel_id: ChannelId,
/// A nonce for enforcing replay protection and ordering.
pub nonce: u64,
/// An id for tracing the message on its route (has no role in bridge consensus)
pub message_id: H256,
/// The inner payload generated from the source application.
pub payload: Vec<u8>,
}
#[derive(Copy, Clone, RuntimeDebug)]
pub struct EnvelopeDecodeError;
impl TryFrom<&Log> for Envelope {
type Error = EnvelopeDecodeError;
fn try_from(log: &Log) -> Result<Self, Self::Error> {
let topics: Vec<B256> = log.topics.iter().map(|x| B256::from_slice(x.as_ref())).collect();
let event = OutboundMessageAccepted::decode_raw_log_validate(topics, &log.data)
.map_err(|_| EnvelopeDecodeError)?;
Ok(Self {
gateway: log.address,
channel_id: ChannelId::from(event.channel_id.as_ref()),
nonce: event.nonce,
message_id: H256::from(event.message_id.as_ref()),
payload: event.payload.into(),
})
}
}
@@ -0,0 +1,384 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
//! Inbound Queue
//!
//! # Overview
//!
//! Receives messages emitted by the Gateway contract on Ethereum, whereupon they are verified,
//! translated to XCM, and finally sent to their final destination teyrchain.
//!
//! The message relayers are rewarded using native currency from the sovereign account of the
//! destination teyrchain.
//!
//! # Extrinsics
//!
//! ## Governance
//!
//! * [`Call::set_operating_mode`]: Set the operating mode of the pallet. Can be used to disable
//! processing of inbound messages.
//!
//! ## Message Submission
//!
//! * [`Call::submit`]: Submit a message for verification and dispatch the final destination
//! teyrchain.
#![cfg_attr(not(feature = "std"), no_std)]
mod envelope;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod test;
use codec::{Decode, DecodeAll, Encode};
use envelope::Envelope;
use frame_support::{
traits::{
fungible::{Inspect, Mutate},
tokens::{Fortitude, Preservation},
},
weights::WeightToFee,
PalletError,
};
use frame_system::ensure_signed;
use scale_info::TypeInfo;
use sp_core::H160;
use sp_runtime::traits::Zero;
use sp_std::vec;
use xcm::prelude::{
send_xcm, Junction::*, Location, SendError as XcmpSendError, SendXcm, Xcm, XcmContext, XcmHash,
};
use xcm_executor::traits::TransactAsset;
use snowbridge_core::{
sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters,
StaticLookup,
};
use snowbridge_inbound_queue_primitives::{
v1::{ConvertMessage, ConvertMessageError, VersionedMessage},
EventProof, VerificationError, Verifier,
};
use sp_runtime::{traits::Saturating, SaturatedConversion, TokenError};
pub use weights::WeightInfo;
type BalanceOf<T> =
<<T as pallet::Config>::Token as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
pub use pallet::*;
pub const LOG_TARGET: &str = "snowbridge-inbound-queue";
#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use sp_core::H256;
#[cfg(feature = "runtime-benchmarks")]
use snowbridge_inbound_queue_primitives::EventFixture;
#[pallet::pallet]
pub struct Pallet<T>(_);
#[cfg(feature = "runtime-benchmarks")]
pub trait BenchmarkHelper<T> {
fn initialize_storage() -> EventFixture;
}
#[pallet::config]
pub trait Config: frame_system::Config {
#[allow(deprecated)]
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// The verifier for inbound messages from Ethereum
type Verifier: Verifier;
/// Message relayers are rewarded with this asset
type Token: Mutate<Self::AccountId> + Inspect<Self::AccountId>;
/// XCM message sender
type XcmSender: SendXcm;
// Address of the Gateway contract
#[pallet::constant]
type GatewayAddress: Get<H160>;
/// Convert inbound message to XCM
type MessageConverter: ConvertMessage<
AccountId = Self::AccountId,
Balance = BalanceOf<Self>,
>;
/// Lookup a channel descriptor
type ChannelLookup: StaticLookup<Source = ChannelId, Target = Channel>;
/// Lookup pricing parameters
type PricingParameters: Get<PricingParameters<BalanceOf<Self>>>;
type WeightInfo: WeightInfo;
#[cfg(feature = "runtime-benchmarks")]
type Helper: BenchmarkHelper<Self>;
/// Convert a weight value into deductible balance type.
type WeightToFee: WeightToFee<Balance = BalanceOf<Self>>;
/// Convert a length value into deductible balance type
type LengthToFee: WeightToFee<Balance = BalanceOf<Self>>;
/// The upper limit here only used to estimate delivery cost
type MaxMessageSize: Get<u32>;
/// To withdraw and deposit an asset.
type AssetTransactor: TransactAsset;
}
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// A message was received from Ethereum
MessageReceived {
/// The message channel
channel_id: ChannelId,
/// The message nonce
nonce: u64,
/// ID of the XCM message which was forwarded to the final destination teyrchain
message_id: [u8; 32],
/// Fee burned for the teleport
fee_burned: BalanceOf<T>,
},
/// Set OperatingMode
OperatingModeChanged { mode: BasicOperatingMode },
}
#[pallet::error]
pub enum Error<T> {
/// Message came from an invalid outbound channel on the Ethereum side.
InvalidGateway,
/// Message has an invalid envelope.
InvalidEnvelope,
/// Message has an unexpected nonce.
InvalidNonce,
/// Message has an invalid payload.
InvalidPayload,
/// Message channel is invalid
InvalidChannel,
/// The max nonce for the type has been reached
MaxNonceReached,
/// Cannot convert location
InvalidAccountConversion,
/// Pallet is halted
Halted,
/// Message verification error,
Verification(VerificationError),
/// XCMP send failure
Send(SendError),
/// Message conversion error
ConvertMessage(ConvertMessageError),
}
#[derive(
Clone, Encode, Decode, DecodeWithMemTracking, Eq, PartialEq, Debug, TypeInfo, PalletError,
)]
pub enum SendError {
NotApplicable,
NotRoutable,
Transport,
DestinationUnsupported,
ExceedsMaxMessageSize,
MissingArgument,
Fees,
}
impl<T: Config> From<XcmpSendError> for Error<T> {
fn from(e: XcmpSendError) -> Self {
match e {
XcmpSendError::NotApplicable => Error::<T>::Send(SendError::NotApplicable),
XcmpSendError::Unroutable => Error::<T>::Send(SendError::NotRoutable),
XcmpSendError::Transport(_) => Error::<T>::Send(SendError::Transport),
XcmpSendError::DestinationUnsupported =>
Error::<T>::Send(SendError::DestinationUnsupported),
XcmpSendError::ExceedsMaxMessageSize =>
Error::<T>::Send(SendError::ExceedsMaxMessageSize),
XcmpSendError::MissingArgument => Error::<T>::Send(SendError::MissingArgument),
XcmpSendError::Fees => Error::<T>::Send(SendError::Fees),
}
}
}
/// The current nonce for each channel
#[pallet::storage]
pub type Nonce<T: Config> = StorageMap<_, Twox64Concat, ChannelId, u64, ValueQuery>;
/// The current operating mode of the pallet.
#[pallet::storage]
#[pallet::getter(fn operating_mode)]
pub type OperatingMode<T: Config> = StorageValue<_, BasicOperatingMode, ValueQuery>;
#[pallet::call]
impl<T: Config> Pallet<T> {
/// Submit an inbound message originating from the Gateway contract on Ethereum
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::submit())]
pub fn submit(origin: OriginFor<T>, event: EventProof) -> DispatchResult {
let who = ensure_signed(origin)?;
ensure!(!Self::operating_mode().is_halted(), Error::<T>::Halted);
// submit message to verifier for verification
T::Verifier::verify(&event.event_log, &event.proof)
.map_err(|e| Error::<T>::Verification(e))?;
// Decode event log into an Envelope
let envelope =
Envelope::try_from(&event.event_log).map_err(|_| Error::<T>::InvalidEnvelope)?;
// Verify that the message was submitted from the known Gateway contract
ensure!(T::GatewayAddress::get() == envelope.gateway, Error::<T>::InvalidGateway);
// Retrieve the registered channel for this message
let channel =
T::ChannelLookup::lookup(envelope.channel_id).ok_or(Error::<T>::InvalidChannel)?;
// Verify message nonce
<Nonce<T>>::try_mutate(envelope.channel_id, |nonce| -> DispatchResult {
if *nonce == u64::MAX {
return Err(Error::<T>::MaxNonceReached.into());
}
if envelope.nonce != nonce.saturating_add(1) {
Err(Error::<T>::InvalidNonce.into())
} else {
*nonce = nonce.saturating_add(1);
Ok(())
}
})?;
// Reward relayer from the sovereign account of the destination teyrchain, only if funds
// are available
let sovereign_account = sibling_sovereign_account::<T>(channel.para_id);
let delivery_cost = Self::calculate_delivery_cost(event.encode().len() as u32);
let amount = T::Token::reducible_balance(
&sovereign_account,
Preservation::Preserve,
Fortitude::Polite,
)
.min(delivery_cost);
if !amount.is_zero() {
T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?;
}
// Decode payload into `VersionedMessage`
let message = VersionedMessage::decode_all(&mut envelope.payload.as_ref())
.map_err(|_| Error::<T>::InvalidPayload)?;
// Decode message into XCM
let (xcm, fee) = Self::do_convert(envelope.message_id, message.clone())?;
tracing::info!(
target: LOG_TARGET,
?xcm,
?fee,
"💫 xcm decoded"
);
// Burning fees for teleport
Self::burn_fees(channel.para_id, fee)?;
// Attempt to send XCM to a dest teyrchain
let message_id = Self::send_xcm(xcm, channel.para_id)?;
Self::deposit_event(Event::MessageReceived {
channel_id: envelope.channel_id,
nonce: envelope.nonce,
message_id,
fee_burned: fee,
});
Ok(())
}
/// Halt or resume all pallet operations. May only be called by root.
#[pallet::call_index(1)]
#[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))]
pub fn set_operating_mode(
origin: OriginFor<T>,
mode: BasicOperatingMode,
) -> DispatchResult {
ensure_root(origin)?;
OperatingMode::<T>::set(mode);
Self::deposit_event(Event::OperatingModeChanged { mode });
Ok(())
}
}
impl<T: Config> Pallet<T> {
pub fn do_convert(
message_id: H256,
message: VersionedMessage,
) -> Result<(Xcm<()>, BalanceOf<T>), Error<T>> {
let (xcm, fee) = T::MessageConverter::convert(message_id, message)
.map_err(|e| Error::<T>::ConvertMessage(e))?;
Ok((xcm, fee))
}
pub fn send_xcm(xcm: Xcm<()>, dest: ParaId) -> Result<XcmHash, Error<T>> {
let dest = Location::new(1, [Teyrchain(dest.into())]);
let (xcm_hash, _) = send_xcm::<T::XcmSender>(dest, xcm).map_err(Error::<T>::from)?;
Ok(xcm_hash)
}
pub fn calculate_delivery_cost(length: u32) -> BalanceOf<T> {
let weight_fee = T::WeightToFee::weight_to_fee(&T::WeightInfo::submit());
let len_fee = T::LengthToFee::weight_to_fee(&Weight::from_parts(length as u64, 0));
weight_fee
.saturating_add(len_fee)
.saturating_add(T::PricingParameters::get().rewards.local)
}
/// Burn the amount of the fee embedded into the XCM for teleports
pub fn burn_fees(para_id: ParaId, fee: BalanceOf<T>) -> DispatchResult {
let dummy_context =
XcmContext { origin: None, message_id: Default::default(), topic: None };
let dest = Location::new(1, [Teyrchain(para_id.into())]);
let fees = (Location::parent(), fee.saturated_into::<u128>()).into();
T::AssetTransactor::can_check_out(&dest, &fees, &dummy_context).map_err(|error| {
tracing::error!(
target: LOG_TARGET,
?error,
"XCM asset check out failed with error"
);
TokenError::FundsUnavailable
})?;
T::AssetTransactor::check_out(&dest, &fees, &dummy_context);
T::AssetTransactor::withdraw_asset(&fees, &dest, None).map_err(|error| {
tracing::error!(
target: LOG_TARGET,
?error,
"XCM asset withdraw failed with error"
);
TokenError::FundsUnavailable
})?;
Ok(())
}
}
/// API for accessing the delivery cost of a message
impl<T: Config> Get<BalanceOf<T>> for Pallet<T> {
fn get() -> BalanceOf<T> {
// Cost here based on MaxMessagePayloadSize(the worst case)
Self::calculate_delivery_cost(T::MaxMessageSize::get())
}
}
}
@@ -0,0 +1,358 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use super::*;
use frame_support::{derive_impl, parameter_types, traits::ConstU32, weights::IdentityFee};
use hex_literal::hex;
use snowbridge_beacon_primitives::{
types::deneb, BeaconHeader, ExecutionProof, Fork, ForkVersions, VersionedExecutionPayloadHeader,
};
use snowbridge_core::{
gwei, meth, Channel, ChannelId, PricingParameters, Rewards, StaticLookup, TokenId,
};
use snowbridge_inbound_queue_primitives::{v1::MessageToXcm, Log, Proof, VerificationError};
use sp_core::{H160, H256};
use sp_runtime::{
traits::{IdentifyAccount, IdentityLookup, MaybeConvert, Verify},
BuildStorage, FixedU128, MultiSignature,
};
use sp_std::{convert::From, default::Default};
use xcm::{
latest::{SendXcm, ZAGROS_GENESIS_HASH},
prelude::*,
};
use xcm_executor::AssetsInHolding;
#[cfg(feature = "runtime-benchmarks")]
use snowbridge_inbound_queue_primitives::EventFixture;
#[cfg(feature = "runtime-benchmarks")]
use snowbridge_pallet_inbound_queue_fixtures::register_token::make_register_token_message;
use crate::{self as inbound_queue};
type Block = frame_system::mocking::MockBlock<Test>;
frame_support::construct_runtime!(
pub enum Test
{
System: frame_system::{Pallet, Call, Storage, Event<T>},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
EthereumBeaconClient: snowbridge_pallet_ethereum_client::{Pallet, Call, Storage, Event<T>},
InboundQueue: inbound_queue::{Pallet, Call, Storage, Event<T>},
}
);
pub type Signature = MultiSignature;
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
type Balance = u128;
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
type AccountId = AccountId;
type Lookup = IdentityLookup<Self::AccountId>;
type AccountData = pallet_balances::AccountData<u128>;
type Block = Block;
}
parameter_types! {
pub const ExistentialDeposit: u128 = 1;
}
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
impl pallet_balances::Config for Test {
type Balance = Balance;
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
}
parameter_types! {
pub const ChainForkVersions: ForkVersions = ForkVersions {
genesis: Fork {
version: hex!("00000001"),
epoch: 0,
},
altair: Fork {
version: hex!("01000001"),
epoch: 0,
},
bellatrix: Fork {
version: hex!("02000001"),
epoch: 0,
},
capella: Fork {
version: hex!("03000001"),
epoch: 0,
},
deneb: Fork {
version: hex!("04000001"),
epoch: 0,
},
electra: Fork {
version: hex!("05000000"),
epoch: 80000000000,
},
fulu: Fork {
version: hex!("06000000"),
epoch: 80000000001,
}
};
}
impl snowbridge_pallet_ethereum_client::Config for Test {
type RuntimeEvent = RuntimeEvent;
type ForkVersions = ChainForkVersions;
type FreeHeadersInterval = ConstU32<32>;
type WeightInfo = ();
}
// Mock verifier
pub struct MockVerifier;
impl Verifier for MockVerifier {
fn verify(_: &Log, _: &Proof) -> Result<(), VerificationError> {
Ok(())
}
}
const GATEWAY_ADDRESS: [u8; 20] = hex!["eda338e4dc46038493b885327842fd3e301cab39"];
parameter_types! {
pub const EthereumNetwork: xcm::v3::NetworkId = xcm::v3::NetworkId::Ethereum { chain_id: 11155111 };
pub const GatewayAddress: H160 = H160(GATEWAY_ADDRESS);
pub const CreateAssetCall: [u8;2] = [53, 0];
pub const CreateAssetExecutionFee: u128 = 2_000_000_000;
pub const CreateAssetDeposit: u128 = 100_000_000_000;
pub const SendTokenExecutionFee: u128 = 1_000_000_000;
pub const InitialFund: u128 = 1_000_000_000_000;
pub const InboundQueuePalletInstance: u8 = 80;
pub UniversalLocation: InteriorLocation =
[GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH)), Teyrchain(1002)].into();
pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(ByGenesis(ZAGROS_GENESIS_HASH)),Teyrchain(1000)]);
}
#[cfg(feature = "runtime-benchmarks")]
impl<T: snowbridge_pallet_ethereum_client::Config> BenchmarkHelper<T> for Test {
fn initialize_storage() -> EventFixture {
make_register_token_message()
}
}
// Mock XCM sender that always succeeds
pub struct MockXcmSender;
impl SendXcm for MockXcmSender {
type Ticket = Xcm<()>;
fn validate(
dest: &mut Option<Location>,
xcm: &mut Option<Xcm<()>>,
) -> SendResult<Self::Ticket> {
if let Some(location) = dest {
match location.unpack() {
(_, [Teyrchain(1001)]) => return Err(XcmpSendError::NotApplicable),
_ => Ok((xcm.clone().unwrap(), Assets::default())),
}
} else {
Ok((xcm.clone().unwrap(), Assets::default()))
}
}
fn deliver(xcm: Self::Ticket) -> core::result::Result<XcmHash, XcmpSendError> {
let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
Ok(hash)
}
}
parameter_types! {
pub const OwnParaId: ParaId = ParaId::new(1013);
pub Parameters: PricingParameters<u128> = PricingParameters {
exchange_rate: FixedU128::from_rational(1, 400),
fee_per_gas: gwei(20),
rewards: Rewards { local: HEZ, remote: meth(1) },
multiplier: FixedU128::from_rational(1, 1),
};
}
pub const HEZ: u128 = 10_000_000_000;
pub struct MockChannelLookup;
impl StaticLookup for MockChannelLookup {
type Source = ChannelId;
type Target = Channel;
fn lookup(channel_id: Self::Source) -> Option<Self::Target> {
if channel_id !=
hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into()
{
return None;
}
Some(Channel { agent_id: H256::zero(), para_id: ASSET_HUB_PARAID.into() })
}
}
pub struct SuccessfulTransactor;
impl TransactAsset for SuccessfulTransactor {
fn can_check_in(_origin: &Location, _what: &Asset, _context: &XcmContext) -> XcmResult {
Ok(())
}
fn can_check_out(_dest: &Location, _what: &Asset, _context: &XcmContext) -> XcmResult {
Ok(())
}
fn deposit_asset(_what: &Asset, _who: &Location, _context: Option<&XcmContext>) -> XcmResult {
Ok(())
}
fn withdraw_asset(
_what: &Asset,
_who: &Location,
_context: Option<&XcmContext>,
) -> Result<AssetsInHolding, XcmError> {
Ok(AssetsInHolding::default())
}
fn internal_transfer_asset(
_what: &Asset,
_from: &Location,
_to: &Location,
_context: &XcmContext,
) -> Result<AssetsInHolding, XcmError> {
Ok(AssetsInHolding::default())
}
}
pub struct MockTokenIdConvert;
impl MaybeConvert<TokenId, Location> for MockTokenIdConvert {
fn maybe_convert(_id: TokenId) -> Option<Location> {
Some(Location::parent())
}
}
impl inbound_queue::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Verifier = MockVerifier;
type Token = Balances;
type XcmSender = MockXcmSender;
type WeightInfo = ();
type GatewayAddress = GatewayAddress;
type MessageConverter = MessageToXcm<
CreateAssetCall,
CreateAssetDeposit,
InboundQueuePalletInstance,
AccountId,
Balance,
MockTokenIdConvert,
UniversalLocation,
AssetHubFromEthereum,
>;
type PricingParameters = Parameters;
type ChannelLookup = MockChannelLookup;
#[cfg(feature = "runtime-benchmarks")]
type Helper = Test;
type WeightToFee = IdentityFee<u128>;
type LengthToFee = IdentityFee<u128>;
type MaxMessageSize = ConstU32<1024>;
type AssetTransactor = SuccessfulTransactor;
}
pub fn setup() {
System::set_block_number(1);
Balances::mint_into(
&sibling_sovereign_account::<Test>(ASSET_HUB_PARAID.into()),
InitialFund::get(),
)
.unwrap();
Balances::mint_into(
&sibling_sovereign_account::<Test>(TEMPLATE_PARAID.into()),
InitialFund::get(),
)
.unwrap();
}
pub fn new_tester() -> sp_io::TestExternalities {
let storage = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
let mut ext: sp_io::TestExternalities = storage.into();
ext.execute_with(setup);
ext
}
// Generated from smoketests:
// cd smoketests
// ./make-bindings
// cargo test --test register_token -- --nocapture
pub fn mock_event_log() -> Log {
Log {
// gateway address
address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(),
topics: vec![
hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(),
// channel id
hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(),
// message id
hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(),
],
// Nonce + Payload
data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d00e40b54020000000000000000000000000000000000000000000000000000000000").into(),
}
}
pub fn mock_event_log_invalid_channel() -> Log {
Log {
address: hex!("eda338e4dc46038493b885327842fd3e301cab39").into(),
topics: vec![
hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(),
// invalid channel id
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(),
],
data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(),
}
}
pub fn mock_event_log_invalid_gateway() -> Log {
Log {
// gateway address
address: H160::zero(),
topics: vec![
hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(),
// channel id
hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(),
// message id
hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(),
],
// Nonce + Payload
data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001e000f000000000000000087d1f7fdfee7f651fabc8bfcb6e086c278b77a7d0000").into(),
}
}
pub fn mock_execution_proof() -> ExecutionProof {
ExecutionProof {
header: BeaconHeader::default(),
ancestry_proof: None,
execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader {
parent_hash: Default::default(),
fee_recipient: Default::default(),
state_root: Default::default(),
receipts_root: Default::default(),
logs_bloom: vec![],
prev_randao: Default::default(),
block_number: 0,
gas_limit: 0,
gas_used: 0,
timestamp: 0,
extra_data: vec![],
base_fee_per_gas: Default::default(),
block_hash: Default::default(),
transactions_root: Default::default(),
withdrawals_root: Default::default(),
blob_gas_used: 0,
excess_blob_gas: 0,
}),
execution_branch: vec![],
}
}
pub const ASSET_HUB_PARAID: u32 = 1000u32;
pub const TEMPLATE_PARAID: u32 = 1001u32;
@@ -0,0 +1,245 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
use super::*;
use frame_support::{assert_noop, assert_ok};
use hex_literal::hex;
use snowbridge_core::ChannelId;
use snowbridge_inbound_queue_primitives::Proof;
use sp_keyring::Sr25519Keyring as Keyring;
use sp_runtime::DispatchError;
use sp_std::convert::From;
use crate::Error;
use crate::mock::*;
#[test]
fn test_submit_happy_path() {
new_tester().execute_with(|| {
let relayer: AccountId = Keyring::Bob.into();
let channel_sovereign = sibling_sovereign_account::<Test>(ASSET_HUB_PARAID.into());
let origin = RuntimeOrigin::signed(relayer.clone());
// Submit event proof
let event = EventProof {
event_log: mock_event_log(),
proof: Proof {
receipt_proof: Default::default(),
execution_proof: mock_execution_proof(),
},
};
let initial_fund = InitialFund::get();
assert_eq!(Balances::balance(&relayer), 0);
assert_eq!(Balances::balance(&channel_sovereign), initial_fund);
assert_ok!(InboundQueue::submit(origin.clone(), event.clone()));
let pallet_events = frame_system::Pallet::<Test>::events();
assert!(
pallet_events.iter().any(|event| matches!(
event.event,
RuntimeEvent::InboundQueue(Event::MessageReceived { nonce, ..})
if nonce == 1
)),
"no event emit."
);
let delivery_cost = InboundQueue::calculate_delivery_cost(event.encode().len() as u32);
assert!(
Parameters::get().rewards.local < delivery_cost,
"delivery cost exceeds pure reward"
);
assert_eq!(Balances::balance(&relayer), delivery_cost, "relayer was rewarded");
assert!(
Balances::balance(&channel_sovereign) <= initial_fund - delivery_cost,
"sovereign account paid reward"
);
});
}
#[test]
fn test_submit_xcm_invalid_channel() {
new_tester().execute_with(|| {
let relayer: AccountId = Keyring::Bob.into();
let origin = RuntimeOrigin::signed(relayer);
// Deposit funds into sovereign account of teyrchain 1001
let sovereign_account = sibling_sovereign_account::<Test>(TEMPLATE_PARAID.into());
println!("account: {}", sovereign_account);
let _ = Balances::mint_into(&sovereign_account, 10000);
// Submit event proof
let event = EventProof {
event_log: mock_event_log_invalid_channel(),
proof: Proof {
receipt_proof: Default::default(),
execution_proof: mock_execution_proof(),
},
};
assert_noop!(
InboundQueue::submit(origin.clone(), event.clone()),
Error::<Test>::InvalidChannel,
);
});
}
#[test]
fn test_submit_with_invalid_gateway() {
new_tester().execute_with(|| {
let relayer: AccountId = Keyring::Bob.into();
let origin = RuntimeOrigin::signed(relayer);
// Deposit funds into sovereign account of Asset Hub (Statemint)
let sovereign_account = sibling_sovereign_account::<Test>(ASSET_HUB_PARAID.into());
let _ = Balances::mint_into(&sovereign_account, 10000);
// Submit event proof
let event = EventProof {
event_log: mock_event_log_invalid_gateway(),
proof: Proof {
receipt_proof: Default::default(),
execution_proof: mock_execution_proof(),
},
};
assert_noop!(
InboundQueue::submit(origin.clone(), event.clone()),
Error::<Test>::InvalidGateway
);
});
}
#[test]
fn test_submit_with_invalid_nonce() {
new_tester().execute_with(|| {
let relayer: AccountId = Keyring::Bob.into();
let origin = RuntimeOrigin::signed(relayer);
// Deposit funds into sovereign account of Asset Hub (Statemint)
let sovereign_account = sibling_sovereign_account::<Test>(ASSET_HUB_PARAID.into());
let _ = Balances::mint_into(&sovereign_account, 10000);
// Submit message
let event = EventProof {
event_log: mock_event_log(),
proof: Proof {
receipt_proof: Default::default(),
execution_proof: mock_execution_proof(),
},
};
assert_ok!(InboundQueue::submit(origin.clone(), event.clone()));
let nonce: u64 = <Nonce<Test>>::get(ChannelId::from(hex!(
"c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539"
)));
assert_eq!(nonce, 1);
// Submit the same again
assert_noop!(
InboundQueue::submit(origin.clone(), event.clone()),
Error::<Test>::InvalidNonce
);
});
}
#[test]
fn test_submit_no_funds_to_reward_relayers_just_ignore() {
new_tester().execute_with(|| {
let relayer: AccountId = Keyring::Bob.into();
let origin = RuntimeOrigin::signed(relayer);
// Reset balance of sovereign_account to zero first
let sovereign_account = sibling_sovereign_account::<Test>(ASSET_HUB_PARAID.into());
Balances::set_balance(&sovereign_account, 0);
// Submit message
let event = EventProof {
event_log: mock_event_log(),
proof: Proof {
receipt_proof: Default::default(),
execution_proof: mock_execution_proof(),
},
};
// Check submit successfully in case no funds available
assert_ok!(InboundQueue::submit(origin.clone(), event.clone()));
});
}
#[test]
fn test_set_operating_mode() {
new_tester().execute_with(|| {
let relayer: AccountId = Keyring::Bob.into();
let origin = RuntimeOrigin::signed(relayer);
let event = EventProof {
event_log: mock_event_log(),
proof: Proof {
receipt_proof: Default::default(),
execution_proof: mock_execution_proof(),
},
};
assert_ok!(InboundQueue::set_operating_mode(
RuntimeOrigin::root(),
snowbridge_core::BasicOperatingMode::Halted
));
assert_noop!(InboundQueue::submit(origin, event), Error::<Test>::Halted);
});
}
#[test]
fn test_set_operating_mode_root_only() {
new_tester().execute_with(|| {
assert_noop!(
InboundQueue::set_operating_mode(
RuntimeOrigin::signed(Keyring::Bob.into()),
snowbridge_core::BasicOperatingMode::Halted
),
DispatchError::BadOrigin
);
});
}
#[test]
fn test_submit_no_funds_to_reward_relayers_and_ed_preserved() {
new_tester().execute_with(|| {
let relayer: AccountId = Keyring::Bob.into();
let origin = RuntimeOrigin::signed(relayer);
// Reset balance of sovereign account to (ED+1) first
let sovereign_account = sibling_sovereign_account::<Test>(ASSET_HUB_PARAID.into());
Balances::set_balance(&sovereign_account, ExistentialDeposit::get() + 1);
// Submit message successfully
let event = EventProof {
event_log: mock_event_log(),
proof: Proof {
receipt_proof: Default::default(),
execution_proof: mock_execution_proof(),
},
};
assert_ok!(InboundQueue::submit(origin.clone(), event.clone()));
// Check balance of sovereign account to ED
let amount = Balances::balance(&sovereign_account);
assert_eq!(amount, ExistentialDeposit::get());
// Submit another message with nonce set as 2
let mut event_log = mock_event_log();
event_log.data[31] = 2;
let event = EventProof {
event_log,
proof: Proof {
receipt_proof: Default::default(),
execution_proof: mock_execution_proof(),
},
};
assert_ok!(InboundQueue::submit(origin.clone(), event.clone()));
// Check balance of sovereign account as ED does not change
let amount = Balances::balance(&sovereign_account);
assert_eq!(amount, ExistentialDeposit::get());
});
}
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
//! Autogenerated weights for `snowbridge_inbound_queue`
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-07-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `macbook pro 14 m2`, CPU: `m2-arm64`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-pezkuwichain-dev"), DB CACHE: 1024
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use sp_std::marker::PhantomData;
/// Weight functions needed for ethereum_beacon_client.
pub trait WeightInfo {
fn submit() -> Weight;
}
// For backwards compatibility and tests
impl WeightInfo for () {
fn submit() -> Weight {
Weight::from_parts(70_000_000, 0)
.saturating_add(Weight::from_parts(0, 3601))
.saturating_add(RocksDbWeight::get().reads(2))
.saturating_add(RocksDbWeight::get().writes(2))
}
}