From 568c5aec7ec8d314123886e64e94172db6332c26 Mon Sep 17 00:00:00 2001 From: Freddyli7 Date: Thu, 2 Nov 2023 15:25:18 -0400 Subject: [PATCH 01/30] add asset transactor and the structure --- bridge/src/lib.rs | 1 + bridge/src/xcm_asset_transactor.rs | 46 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 bridge/src/xcm_asset_transactor.rs diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index 2e943d9f..90c5f1cf 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -19,6 +19,7 @@ mod encode; #[cfg(test)] mod mock; +mod xcm_asset_transactor; #[allow(unused_variables)] #[allow(clippy::large_enum_variant)] diff --git a/bridge/src/xcm_asset_transactor.rs b/bridge/src/xcm_asset_transactor.rs new file mode 100644 index 00000000..db8fcb0c --- /dev/null +++ b/bridge/src/xcm_asset_transactor.rs @@ -0,0 +1,46 @@ +use xcm::latest::{Junctions, MultiAsset, MultiLocation, XcmContext}; +use xcm::prelude::{GeneralKey, X3}; +use xcm::v3::Junction::Parachain; +use xcm_executor::{traits::TransactAsset}; + +pub struct XCMAssetTransactor; + +impl TransactAsset for XCMAssetTransactor{ + // deposit_asset implements the TransactAsset deposit_asset method and contains the logic to classify + // the asset recipient location: + // 1. recipient is on the local parachain + // 2. recipient is on the remote parachain + // 3, recipient is on non-substrate chain(evm, cosmos, etc.) + fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext){ + match (who.parents, who.interior) { + // 1. recipient is the local parachain + (0, None) => { + // TODO: check if the asset is native or foreign, and call the corresponding deposit_asset() + } + // 2. recipient is remote parachain + (1, Some(Parachain(_))) => { + // TODO: call the xcm handler pallet to construct the xcm message (evm to remote parachain route) + // xcm message must have a sender(origin), so a tmp account derived from pallet would be used + // check if the asset is native or foreign, and call the corresponding deposit_asset(), recipient will be the derived tmp account + // xcm message execution + + // trying to eliminate the forward logic here by adding the XCM handler pallet as one of the generic type for XCMAssetTransactor + } + // 3. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet + // TODO: the junctions below is just an temporary example, will change it to proper sygma bridge standard, see the link below: + // (https://www.notion.so/chainsafe/Sygma-as-an-Independent-pallet-c481f00ccff84ff49ce917c8b2feacda?pvs=4#6e51e6632e254b9b9a01444ef7297969) + (0, &X3(Parachain(_), GeneralKey{length: 8, data: [1u8, 32]}, GeneralKey {length:8, data: [2u8, 32]})) => { + // TODO: check if the asset is native or foreign, and deposit the asset to a tmp account first + // TODO: call deposit() extrisic in sygmaBrdige pallet + } + // Other destination multilocation not supported, return Err + _ => { + Err("Destination not supported") + } + } + } + + fn withdraw_asset(_what: &MultiAsset, _who: &MultiLocation, _maybe_context: Option<&XcmContext>,){ + // TODO: + } +} From 3044a0e043a6dcf247aa5beaba5bfde4ccd75b10 Mon Sep 17 00:00:00 2001 From: Freddyli7 Date: Fri, 3 Nov 2023 12:17:21 -0400 Subject: [PATCH 02/30] add generic type for XCM asset transactor with forwarder traits --- bridge/src/xcm_asset_transactor.rs | 42 +++++++++++++++++++++++------- traits/src/lib.rs | 12 +++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/bridge/src/xcm_asset_transactor.rs b/bridge/src/xcm_asset_transactor.rs index db8fcb0c..e0ed4d37 100644 --- a/bridge/src/xcm_asset_transactor.rs +++ b/bridge/src/xcm_asset_transactor.rs @@ -1,11 +1,12 @@ -use xcm::latest::{Junctions, MultiAsset, MultiLocation, XcmContext}; -use xcm::prelude::{GeneralKey, X3}; -use xcm::v3::Junction::Parachain; +use core::marker::PhantomData; +use xcm::latest::{Junction, MultiAsset, MultiLocation, XcmContext}; +use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; +use xcm::prelude::*; use xcm_executor::{traits::TransactAsset}; -pub struct XCMAssetTransactor; +pub struct XCMAssetTransactor(PhantomData<(CurrencyTransactor, FungiblesTransactor, AssetTypeChecker, Forwarder)>); -impl TransactAsset for XCMAssetTransactor{ +impl TransactAsset for XCMAssetTransactor { // deposit_asset implements the TransactAsset deposit_asset method and contains the logic to classify // the asset recipient location: // 1. recipient is on the local parachain @@ -15,23 +16,44 @@ impl TransactAsset for XCMAssetTransactor{ match (who.parents, who.interior) { // 1. recipient is the local parachain (0, None) => { - // TODO: check if the asset is native or foreign, and call the corresponding deposit_asset() + // check if the asset is native or foreign, and call the corresponding deposit_asset() + if AssetTypeChecker::is_native_asset(what) { + CurrencyTransactor::deposit_asset(what, who, context)?; + } else { + FungiblesTransactor::deposit_asset(what, who, context)? + } } // 2. recipient is remote parachain + // trying to eliminate the forward logic here by adding the XCM handler pallet as one of the generic type for XCMAssetTransactor (1, Some(Parachain(_))) => { - // TODO: call the xcm handler pallet to construct the xcm message (evm to remote parachain route) // xcm message must have a sender(origin), so a tmp account derived from pallet would be used + let tmp_account = MultiLocation::new(0, X1(GeneralKey {length: 8, data: [2u8; 32]})).into_account(); + // check if the asset is native or foreign, and call the corresponding deposit_asset(), recipient will be the derived tmp account // xcm message execution + if AssetTypeChecker::is_native_asset(what) { + CurrencyTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; + } else { + FungiblesTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? + } - // trying to eliminate the forward logic here by adding the XCM handler pallet as one of the generic type for XCMAssetTransactor + // TODO: call the xcm handler pallet to construct the xcm message and execute it(to other remote parachain route) + Forwarder::xcm_transactor_forwarder() } // 3. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet // TODO: the junctions below is just an temporary example, will change it to proper sygma bridge standard, see the link below: // (https://www.notion.so/chainsafe/Sygma-as-an-Independent-pallet-c481f00ccff84ff49ce917c8b2feacda?pvs=4#6e51e6632e254b9b9a01444ef7297969) (0, &X3(Parachain(_), GeneralKey{length: 8, data: [1u8, 32]}, GeneralKey {length:8, data: [2u8, 32]})) => { - // TODO: check if the asset is native or foreign, and deposit the asset to a tmp account first - // TODO: call deposit() extrisic in sygmaBrdige pallet + // check if the asset is native or foreign, and deposit the asset to a tmp account first + let tmp_account = MultiLocation::new(0, X1(GeneralKey {length: 8, data: [2u8; 32]})).into_account(); + if AssetTypeChecker::is_native_asset(what) { + CurrencyTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; + } else { + FungiblesTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? + } + + // TODO: call deposit() extrisic in sygmaBrdige pallet. Sygma bridge pallet should also be in the PhantomData type + Forwarder::other_world_transactor_forwarder() } // Other destination multilocation not supported, return Err _ => { diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 60ea32cd..af380905 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -61,3 +61,15 @@ pub trait DecimalConverter { /// Sygma relayer will always send asset in 18 decimal fn convert_from(asset: &MultiAsset) -> Option; } + +// TODO: implement this method for local mock and standalone use +// when integrating with parachain, parachain team can implement their own version +pub trait AssetTypeIdentifier { + fn is_native_asset(asset: &MultiAsset) -> bool; +} + +// TODO: implement these methods +pub trait TransactorForwarder { + fn xcm_transactor_forwarder(); + fn other_world_transactor_forwarder(); +} From 16971565a383cab71a04cae4f293a85f4150d88d Mon Sep 17 00:00:00 2001 From: Freddyli7 Date: Mon, 6 Nov 2023 16:12:56 -0500 Subject: [PATCH 03/30] add bridge forward with trait --- Cargo.lock | 353 +++++++++++++++-------------- Cargo.toml | 1 + bridge-forwarder/Cargo.toml | 52 +++++ bridge-forwarder/src/lib.rs | 52 +++++ bridge/src/lib.rs | 10 +- bridge/src/xcm_asset_transactor.rs | 14 +- traits/src/lib.rs | 18 +- 7 files changed, 320 insertions(+), 180 deletions(-) create mode 100644 bridge-forwarder/Cargo.toml create mode 100644 bridge-forwarder/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 006c2173..34fc1c39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,7 +594,7 @@ dependencies = [ "log", "parking", "polling", - "rustix 0.37.26", + "rustix 0.37.27", "slab", "socket2 0.4.10", "waker-fn", @@ -617,7 +617,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -628,7 +628,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -782,7 +782,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1206,7 +1206,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1292,9 +1292,9 @@ checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" [[package]] name = "const-random" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11df32a13d7892ec42d51d3d175faba5211ffe13ed25d4fb348ac9e9ce835593" +checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" dependencies = [ "const-random-macro", ] @@ -1358,9 +1358,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -1474,9 +1474,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" @@ -1679,20 +1679,20 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "cxx" -version = "1.0.109" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c390c123d671cc547244943ecad81bdaab756c6ea332d9ca9c1f48d952a24895" +checksum = "7129e341034ecb940c9072817cd9007974ea696844fc4dd582dc1653a7fbe2e8" dependencies = [ "cc", "cxxbridge-flags", @@ -1702,9 +1702,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.109" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00d3d3ac9ffb900304edf51ca719187c779f4001bb544f26c4511d621de905cf" +checksum = "a2a24f3f5f8eed71936f21e570436f024f5c2e25628f7496aa7ccd03b90109d5" dependencies = [ "cc", "codespan-reporting", @@ -1712,24 +1712,24 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "cxxbridge-flags" -version = "1.0.109" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94415827ecfea0f0c74c8cad7d1a86ddb3f05354d6a6ddeda0adee5e875d2939" +checksum = "06fdd177fc61050d63f67f5bd6351fac6ab5526694ea8e359cd9cd3b75857f44" [[package]] name = "cxxbridge-macro" -version = "1.0.109" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33dbbe9f5621c9247f97ec14213b04f350bff4b6cebefe834c60055db266ecf" +checksum = "587663dd5fb3d10932c8aecfe7c844db1bcf0aee93eeab08fac13dc1212c2e7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2002,7 +2002,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2024,18 +2024,18 @@ dependencies = [ [[package]] name = "docify" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee528c501ddd15d5181997e9518e59024844eac44fd1e40cb20ddb2a8562fa" +checksum = "4235e9b248e2ba4b92007fe9c646f3adf0ffde16dc74713eacc92b8bc58d8d2f" dependencies = [ "docify_macros", ] [[package]] name = "docify_macros" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca01728ab2679c464242eca99f94e2ce0514b52ac9ad950e2ed03fca991231c" +checksum = "47020e12d7c7505670d1363dd53d6c23724f71a90a3ae32ff8eba40de8404626" dependencies = [ "common-path", "derive-syn-parse", @@ -2043,7 +2043,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.38", + "syn 2.0.39", "termcolor", "toml 0.7.8", "walkdir", @@ -2084,9 +2084,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" [[package]] name = "ecdsa" @@ -2225,7 +2225,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2325,7 +2325,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2399,9 +2399,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d" +checksum = "a481586acf778f1b1455424c343f71124b048ffa5f4fc3f8f6ae9dc432dcb3c7" [[package]] name = "file-per-thread-logger" @@ -2601,7 +2601,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2728,7 +2728,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2740,7 +2740,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2750,7 +2750,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polk dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2838,9 +2838,9 @@ checksum = "aa590387383a574eb0a02370ad4b29c72e6ddd6b0afc2f6e2890bdb4be6d3a92" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -2853,9 +2853,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -2863,15 +2863,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -2881,9 +2881,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-lite" @@ -2902,13 +2902,13 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2924,15 +2924,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-timer" @@ -2942,9 +2942,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -3359,9 +3359,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http", @@ -3371,7 +3371,7 @@ dependencies = [ "rustls-native-certs", "tokio", "tokio-rustls", - "webpki-roots 0.23.1", + "webpki-roots 0.25.2", ] [[package]] @@ -3514,9 +3514,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.2", @@ -3623,7 +3623,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.3", - "rustix 0.38.20", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -3653,9 +3653,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -3887,9 +3887,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libloading" @@ -4326,6 +4326,17 @@ dependencies = [ "yamux", ] +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "librocksdb-sys" version = "0.11.0+8.1.1" @@ -4523,7 +4534,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4537,7 +4548,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4548,7 +4559,7 @@ checksum = "d710e1214dffbab3b5dacb21475dde7d6ed84c69ff722b3a47a782668d44fbac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4559,7 +4570,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4621,7 +4632,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.20", + "rustix 0.38.21", ] [[package]] @@ -5894,7 +5905,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5915,7 +5926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.2", + "indexmap 2.1.0", ] [[package]] @@ -5935,7 +5946,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5984,9 +5995,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.1.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4503fa043bf02cee09a9582e9554b4c6403b2ef55e4612e96561d294419429f8" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" [[package]] name = "polkadot-core-primitives" @@ -6213,9 +6224,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b559898e0b4931ed2d3b959ab0c2da4d99cc644c4b0b1a35b4d344027f474023" +checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b" [[package]] name = "powerfmt" @@ -6276,7 +6287,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -6334,7 +6345,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -6380,7 +6391,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -6678,12 +6689,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom 0.2.10", - "redox_syscall 0.2.16", + "libredox", "thiserror", ] @@ -6704,7 +6715,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -6970,9 +6981,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.16" +version = "0.36.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6da3636faa25820d8648e0e31c5d519bbb01f72fdf57131f0f5f7da5fed36eab" +checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" dependencies = [ "bitflags 1.3.2", "errno", @@ -6984,9 +6995,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.26" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84f3f8f960ed3b5a59055428714943298bf3fa2d4a1d53135084e0544829d995" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags 1.3.2", "errno", @@ -6998,9 +7009,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.20" +version = "0.38.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" dependencies = [ "bitflags 2.4.1", "errno", @@ -7042,7 +7053,7 @@ checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", "ring 0.17.5", - "rustls-webpki 0.101.7", + "rustls-webpki", "sct 0.7.1", ] @@ -7067,16 +7078,6 @@ dependencies = [ "base64 0.21.5", ] -[[package]] -name = "rustls-webpki" -version = "0.100.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6a5fc258f1c1276dfe3016516945546e2d5383911efc0fc4f1cdc5df3a4ae3" -dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", -] - [[package]] name = "rustls-webpki" version = "0.101.7" @@ -7213,7 +7214,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -7468,7 +7469,7 @@ dependencies = [ "cfg-if", "libc", "log", - "rustix 0.36.16", + "rustix 0.36.17", "sc-allocator", "sc-executor-common", "sp-runtime-interface", @@ -7980,7 +7981,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -8261,29 +8262,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.190" +version = "1.0.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +checksum = "a834c4821019838224821468552240d4d95d14e751986442c816572d39a080c9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.190" +version = "1.0.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +checksum = "46fa52d5646bce91b680189fe5b1c049d2ea38dabb4e2e7c8d00ca12cfbfbcfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -8557,7 +8558,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -8777,7 +8778,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polk dependencies = [ "quote", "sp-core-hashing", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -8796,7 +8797,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polk dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -8995,7 +8996,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9187,7 +9188,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9419,7 +9420,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9443,9 +9444,9 @@ dependencies = [ [[package]] name = "substrate-bip39" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" +checksum = "e620c7098893ba667438b47169c00aacdd9e7c10e042250ce2b60b087ec97328" dependencies = [ "hmac 0.11.0", "pbkdf2 0.8.0", @@ -9610,6 +9611,25 @@ dependencies = [ "sygma-traits", ] +[[package]] +name = "sygma-bridge-forwarder" +version = "0.3.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-assets", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "sygma-traits", +] + [[package]] name = "sygma-fee-handler-router" version = "0.3.0" @@ -9704,9 +9724,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -9760,14 +9780,14 @@ checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand 2.0.1", - "redox_syscall 0.3.5", - "rustix 0.38.20", + "redox_syscall 0.4.1", + "rustix 0.38.21", "windows-sys 0.48.0", ] @@ -9803,7 +9823,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9950,7 +9970,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -10037,7 +10057,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.1.0", "serde", "serde_spanned", "toml_datetime", @@ -10105,7 +10125,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -10518,9 +10538,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -10528,24 +10548,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -10555,9 +10575,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10565,22 +10585,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "wasm-instrument" @@ -10705,7 +10725,7 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.36.16", + "rustix 0.36.17", "serde", "sha2 0.10.8", "toml 0.5.11", @@ -10801,7 +10821,7 @@ checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" dependencies = [ "object 0.30.4", "once_cell", - "rustix 0.36.16", + "rustix 0.36.17", ] [[package]] @@ -10832,7 +10852,7 @@ dependencies = [ "memoffset 0.8.0", "paste", "rand 0.8.5", - "rustix 0.36.16", + "rustix 0.36.17", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", @@ -10853,9 +10873,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -10890,15 +10910,6 @@ dependencies = [ "webpki 0.22.4", ] -[[package]] -name = "webpki-roots" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338" -dependencies = [ - "rustls-webpki 0.100.3", -] - [[package]] name = "webpki-roots" version = "0.25.2" @@ -11136,7 +11147,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.20", + "rustix 0.38.21", ] [[package]] @@ -11339,9 +11350,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.17" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ "memchr", ] @@ -11433,7 +11444,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -11461,22 +11472,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.15" +version = "0.7.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ba595b9f2772fbee2312de30eeb80ec773b4cb2f1e8098db024afadda6c06f" +checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.15" +version = "0.7.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772666c41fb6dceaf520b564b962d738a8e1a83b41bd48945f50837aed78bb1d" +checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -11496,7 +11507,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e7006060..954b5168 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [ "substrate-node/node", "substrate-node/runtime", "parachain-info", + "bridge-forwarder" ] exclude = [ diff --git a/bridge-forwarder/Cargo.toml b/bridge-forwarder/Cargo.toml new file mode 100644 index 00000000..aec5c2b5 --- /dev/null +++ b/bridge-forwarder/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "sygma-bridge-forwarder" +version = "0.3.0" +edition = "2021" +license = "LGPL-3.0" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde", "decode"] } + +# Substrate +frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } + +# Polkadot +xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } + +# Local +sygma-traits = { path = "../traits", default-features = false } + +[dev-dependencies] +# Substrate +sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } + +sygma-traits = { path = "../traits" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "sp-std/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", + "sygma-traits/std", +] +runtime-benchmarks = [ + 'frame-support/runtime-benchmarks', + 'frame-system/runtime-benchmarks', +] +try-runtime = ["frame-support/try-runtime"] diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs new file mode 100644 index 00000000..8c90b955 --- /dev/null +++ b/bridge-forwarder/src/lib.rs @@ -0,0 +1,52 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use self::pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + use frame_support::transactional; + use frame_support::traits::StorageVersion; + use sygma_traits::{TransactorForwarder, OtherWorldBridge, InnerWorldBridge}; + use xcm::latest::{prelude::*, MultiAsset, MultiLocation}; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type SygmaBridge: OtherWorldBridge; + type XCMBridge: InnerWorldBridge; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Assets being withdrawn from somewhere. + XCMTransferForward {}, + OtherWorldTransferForward {}, + } + + #[pallet::call] + impl TransactorForwarder for Pallet { + #[pallet::call_index(0)] + #[pallet::weight(Weight::from_parts(195_000_000, 0))] + #[transactional] + pub fn xcm_transactor_forwarder(origin: OriginFor, what: MultiAsset, who: MultiLocation) -> DispatchResult { + T::XCMBridge::create_message()?; + T::XCMBridge::execute_message()? + } + + #[pallet::call_index(1)] + #[pallet::weight(Weight::from_parts(195_000_000, 0))] + #[transactional] + pub fn other_world_transactor_forwarder(origin: OriginFor, what: MultiAsset, who: MultiLocation) -> DispatchResult { + T::SygmaBridge::deposit(origin.into(), what, who)? + } + } +} diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index 90c5f1cf..73db7666 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -51,7 +51,7 @@ pub mod pallet { use sp_std::collections::btree_map::BTreeMap; use sygma_traits::{ ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, - MpcAddress, ResourceId, TransferType, VerifyingContractAddress, + MpcAddress, ResourceId, TransferType, VerifyingContractAddress, OtherWorldBridge, }; #[allow(dead_code)] @@ -683,6 +683,14 @@ pub mod pallet { } } + impl OtherWorldBridge for Pallet { + fn do_deposit(sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation) -> DispatchResult { + &Self::deposit(sender, asset, dest)? + } + } + impl Pallet where ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, diff --git a/bridge/src/xcm_asset_transactor.rs b/bridge/src/xcm_asset_transactor.rs index e0ed4d37..446905f2 100644 --- a/bridge/src/xcm_asset_transactor.rs +++ b/bridge/src/xcm_asset_transactor.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; use xcm::latest::{Junction, MultiAsset, MultiLocation, XcmContext}; use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; use xcm::prelude::*; -use xcm_executor::{traits::TransactAsset}; +use xcm_executor::{Assets, traits::TransactAsset}; pub struct XCMAssetTransactor(PhantomData<(CurrencyTransactor, FungiblesTransactor, AssetTypeChecker, Forwarder)>); @@ -12,7 +12,7 @@ impl XcmResult { match (who.parents, who.interior) { // 1. recipient is the local parachain (0, None) => { @@ -38,7 +38,7 @@ impl { - Err("Destination not supported") + Err(XcmError::DestinationUnsupported) } } + Ok(()) } - fn withdraw_asset(_what: &MultiAsset, _who: &MultiLocation, _maybe_context: Option<&XcmContext>,){ + fn withdraw_asset(_what: &MultiAsset, _who: &MultiLocation, _maybe_context: Option<&XcmContext>) -> Result { // TODO: + Ok(Assets::new()) } } diff --git a/traits/src/lib.rs b/traits/src/lib.rs index af380905..e1df7e8b 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -4,6 +4,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::dispatch::DispatchResult; use primitive_types::{H160, U256}; use scale_info::TypeInfo; use sp_std::vec::Vec; @@ -70,6 +71,19 @@ pub trait AssetTypeIdentifier { // TODO: implement these methods pub trait TransactorForwarder { - fn xcm_transactor_forwarder(); - fn other_world_transactor_forwarder(); + fn xcm_transactor_forwarder(sender: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult; + fn other_world_transactor_forwarder(sender: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult; +} + +pub trait OtherWorldBridge { + fn do_deposit( + sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation, + ) -> DispatchResult; +} + +pub trait InnerWorldBridge { + fn create_message() -> DispatchResult; + fn execute_message() -> DispatchResult; } From 077a55df326e2afe426e37276e06d782fcd070e1 Mon Sep 17 00:00:00 2001 From: Freddyli7 Date: Tue, 7 Nov 2023 09:54:01 -0500 Subject: [PATCH 04/30] added xcm bridge --- Cargo.toml | 3 ++- bridge-forwarder/src/lib.rs | 16 +++++------- bridge/src/lib.rs | 10 +++---- traits/src/lib.rs | 9 ++----- xcm-bridge/Cargo.toml | 52 +++++++++++++++++++++++++++++++++++++ xcm-bridge/src/lib.rs | 38 +++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 xcm-bridge/Cargo.toml create mode 100644 xcm-bridge/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 954b5168..dd190f14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,8 @@ members = [ "substrate-node/node", "substrate-node/runtime", "parachain-info", - "bridge-forwarder" + "bridge-forwarder", + "xcm-bridge" ] exclude = [ diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index 8c90b955..48e2b31b 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -8,7 +8,7 @@ pub mod pallet { use frame_system::pallet_prelude::*; use frame_support::transactional; use frame_support::traits::StorageVersion; - use sygma_traits::{TransactorForwarder, OtherWorldBridge, InnerWorldBridge}; + use sygma_traits::{TransactorForwarder, Bridge}; use xcm::latest::{prelude::*, MultiAsset, MultiLocation}; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -20,14 +20,13 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type SygmaBridge: OtherWorldBridge; - type XCMBridge: InnerWorldBridge; + type SygmaBridge: Bridge; + type XCMBridge: Bridge; } #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Assets being withdrawn from somewhere. XCMTransferForward {}, OtherWorldTransferForward {}, } @@ -37,16 +36,15 @@ pub mod pallet { #[pallet::call_index(0)] #[pallet::weight(Weight::from_parts(195_000_000, 0))] #[transactional] - pub fn xcm_transactor_forwarder(origin: OriginFor, what: MultiAsset, who: MultiLocation) -> DispatchResult { - T::XCMBridge::create_message()?; - T::XCMBridge::execute_message()? + fn xcm_transactor_forwarder(origin: OriginFor, what: MultiAsset, who: MultiLocation) -> DispatchResult { + T::XCMBridge::transfer(origin.into(), what, who)?; } #[pallet::call_index(1)] #[pallet::weight(Weight::from_parts(195_000_000, 0))] #[transactional] - pub fn other_world_transactor_forwarder(origin: OriginFor, what: MultiAsset, who: MultiLocation) -> DispatchResult { - T::SygmaBridge::deposit(origin.into(), what, who)? + fn other_world_transactor_forwarder(origin: OriginFor, what: MultiAsset, who: MultiLocation) -> DispatchResult { + T::SygmaBridge::transfer(origin.into(), what, who)? } } } diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index 73db7666..f161d1fe 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -51,7 +51,7 @@ pub mod pallet { use sp_std::collections::btree_map::BTreeMap; use sygma_traits::{ ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, - MpcAddress, ResourceId, TransferType, VerifyingContractAddress, OtherWorldBridge, + MpcAddress, ResourceId, TransferType, VerifyingContractAddress, Bridge, }; #[allow(dead_code)] @@ -683,10 +683,10 @@ pub mod pallet { } } - impl OtherWorldBridge for Pallet { - fn do_deposit(sender: [u8; 32], - asset: MultiAsset, - dest: MultiLocation) -> DispatchResult { + impl Bridge for Pallet { + fn transfer(sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation) -> DispatchResult { &Self::deposit(sender, asset, dest)? } } diff --git a/traits/src/lib.rs b/traits/src/lib.rs index e1df7e8b..1063be88 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -75,15 +75,10 @@ pub trait TransactorForwarder { fn other_world_transactor_forwarder(sender: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult; } -pub trait OtherWorldBridge { - fn do_deposit( +pub trait Bridge { + fn transfer( sender: [u8; 32], asset: MultiAsset, dest: MultiLocation, ) -> DispatchResult; } - -pub trait InnerWorldBridge { - fn create_message() -> DispatchResult; - fn execute_message() -> DispatchResult; -} diff --git a/xcm-bridge/Cargo.toml b/xcm-bridge/Cargo.toml new file mode 100644 index 00000000..28bb014e --- /dev/null +++ b/xcm-bridge/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "sygma-xcm-bridge" +version = "0.3.0" +edition = "2021" +license = "LGPL-3.0" + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde", "decode"] } + +# Substrate +frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } + +# Polkadot +xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } + +# Local +sygma-traits = { path = "../traits", default-features = false } + +[dev-dependencies] +# Substrate +sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } + +sygma-traits = { path = "../traits" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "sp-std/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", + "sygma-traits/std", +] +runtime-benchmarks = [ + 'frame-support/runtime-benchmarks', + 'frame-system/runtime-benchmarks', +] +try-runtime = ["frame-support/try-runtime"] diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs new file mode 100644 index 00000000..1eb334ac --- /dev/null +++ b/xcm-bridge/src/lib.rs @@ -0,0 +1,38 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +pub use self::pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use sygma_traits::{Bridge}; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + XCMTransferSend {}, + } + + #[pallet::call] + impl Bridge for Pallet { + #[pallet::call_index(0)] + #[pallet::weight(Weight::from_parts(195_000_000, 0))] + #[transactional] + fn transfer(sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation) -> DispatchResult { + // TODO: create xcm message + // TODO: execute xcm message + } + } +} From da30fb971335d2ab3cc4bb806bd1abd519385fb8 Mon Sep 17 00:00:00 2001 From: Freddyli7 Date: Tue, 28 Nov 2023 12:12:57 -0500 Subject: [PATCH 05/30] add xcm message struct and execution logic --- Cargo.lock | 19 ++++++++++++++++++ xcm-bridge/src/lib.rs | 45 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 34fc1c39..fbef786a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9711,6 +9711,25 @@ dependencies = [ "staging-xcm-builder", ] +[[package]] +name = "sygma-xcm-bridge" +version = "0.3.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-assets", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "sygma-traits", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 1eb334ac..50cc869d 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -15,6 +15,10 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + type Weigher: WeightBounds; + + type XcmExecutor: ExecuteXcm; } #[pallet::event] @@ -23,6 +27,47 @@ pub mod pallet { XCMTransferSend {}, } + #[pallet::error] + pub enum Error { + FailToWeightMessage, + XcmExecutionFailed, + } + + struct Xcm{ + asset: MultiAsset, + origin: MultiLocation, + dest: MultiLocation, + recipient: MultiLocation, + weight: XCMWeight, + } + + pub trait XcmHandler { + fn create_message(&self) -> Result, DispatchError>; + fn execute_message(&self, xcm_message: Xcm) -> DispatchResult; + } + + impl XcmHandler for Xcm { + fn create_message(&self) { + + } + + fn execute_message(&self, xcm_message: Xcm) { + let message_weight = T::Weigher::weight(xcm_message).map_err(|()| Error::::FailToWeightMessage)?; + + let hash = xcm_message.using_encoded(sp_io::hashing::blake2_256); + + T::XcmExecutor::execute_xcm_in_credit( + self.origin.clone(), + xcm_message.clone(), + hash, + message_weight, + message_weight + ).ensure_complete().map_err(|_| Error::::XcmExecutionFailed)?; + + oK(()) + } + } + #[pallet::call] impl Bridge for Pallet { #[pallet::call_index(0)] From c44dfbf0fa3f39770c51740fe586e9c8f1b8b05a Mon Sep 17 00:00:00 2001 From: Freddyli7 Date: Mon, 4 Dec 2023 13:32:31 -0500 Subject: [PATCH 06/30] add xcm transfer logic --- xcm-bridge/src/lib.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 50cc869d..3a39325e 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -48,7 +48,10 @@ pub mod pallet { impl XcmHandler for Xcm { fn create_message(&self) { - + // TODO: xcm instructions + // asset reserved on the origin: WithdrawAsset + DepositReserveAsset (BuyExecution + DepositAsset) + // asset reserved on the dest: WithdrawAsset + InitiateReserveWithdraw (BuyExecution + DepositAsset) + // asset not reserved: WithdrawAsset + InitiateReserveWithdraw (BuyExecution + DepositReserveAsset(BuyExecution + DepositAsset)) } fn execute_message(&self, xcm_message: Xcm) { @@ -77,7 +80,23 @@ pub mod pallet { asset: MultiAsset, dest: MultiLocation) -> DispatchResult { // TODO: create xcm message + let origin_location: MultiLocation = Junction::AccountId32 { + network: None, + id: sender, + }.into(); + let xcm = Xcm:: { + asset: asset.clone(), + origin: origin_location.clone(), + dest: MultiLocation, // TODO: extra dest + recipient: MultiLocation, // TODO: extra recipient on dest + recipient: MultiLocation, // TODO: extra recipient on dest + weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), + }; + let mut msg = xcm.create_message()?; // TODO: execute xcm message + xcm.execute_message(msg)?; + + Ok(()) } } } From 3939b6c0d54fe49fbe4dd7e53948a195afc18cec Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Mon, 4 Dec 2023 17:10:08 -0500 Subject: [PATCH 07/30] add 3 types of asset transfer impl --- xcm-bridge/src/lib.rs | 145 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 126 insertions(+), 19 deletions(-) diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 3a39325e..597ab513 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -4,7 +4,7 @@ pub use self::pallet::*; #[frame_support::pallet] pub mod pallet { - use sygma_traits::{Bridge}; + use sygma_traits::Bridge; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -21,8 +21,17 @@ pub mod pallet { type XcmExecutor: ExecuteXcm; } + enum TransferKind { + /// Transfer self reserve asset. + SelfReserveAsset, + /// To reserve location. + ToReserve, + /// To non-reserve location. + ToNonReserve, + } + #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] + #[pallet::generate_deposit(pub (super) fn deposit_event)] pub enum Event { XCMTransferSend {}, } @@ -33,7 +42,7 @@ pub mod pallet { XcmExecutionFailed, } - struct Xcm{ + struct Xcm { asset: MultiAsset, origin: MultiLocation, dest: MultiLocation, @@ -42,29 +51,49 @@ pub mod pallet { } pub trait XcmHandler { - fn create_message(&self) -> Result, DispatchError>; - fn execute_message(&self, xcm_message: Xcm) -> DispatchResult; + fn transfer_kind(&self) -> Result, DispatchError>; + fn create_instructions(&self) -> Result, DispatchError>; + fn execute_instructions(&self, xcm_message: Xcm) -> DispatchResult; } impl XcmHandler for Xcm { - fn create_message(&self) { - // TODO: xcm instructions - // asset reserved on the origin: WithdrawAsset + DepositReserveAsset (BuyExecution + DepositAsset) - // asset reserved on the dest: WithdrawAsset + InitiateReserveWithdraw (BuyExecution + DepositAsset) - // asset not reserved: WithdrawAsset + InitiateReserveWithdraw (BuyExecution + DepositReserveAsset(BuyExecution + DepositAsset)) + /// Get the transfer kind. + fn transfer_kind(&self) -> Result, DispatchError> { + // todo: impl the xcm kind logic, return the following: + // SelfReserveAsset, + // ToReserve, + // ToNonReserve, } + fn create_instructions(&self) { + let kind = Self::transfer_kind(&self)?; + + let mut xcm_instructions = match kind { + SelfReserveAsset => Self::transfer_self_reserve_asset(assets, fee, dest, recipient, dest_weight_limit)?, + ToReserve => Self::transfer_to_reserve_asset(assets, fee, dest, recipient, dest_weight_limit)?, + ToNonReserve => Self::transfer_to_non_reserve_asset( + assets, + fee, + reserve, + dest, + recipient, + dest_weight_limit, + )?, + }; - fn execute_message(&self, xcm_message: Xcm) { - let message_weight = T::Weigher::weight(xcm_message).map_err(|()| Error::::FailToWeightMessage)?; + Ok(xcm_instructions) + } - let hash = xcm_message.using_encoded(sp_io::hashing::blake2_256); + fn execute_instructions(&self, xcm_instructions: Xcm) { + let message_weight = T::Weigher::weight(xcm_instructions).map_err(|()| Error::::FailToWeightMessage)?; + + let hash = xcm_instructions.using_encoded(sp_io::hashing::blake2_256); T::XcmExecutor::execute_xcm_in_credit( self.origin.clone(), - xcm_message.clone(), + xcm_instructions.clone(), hash, message_weight, - message_weight + message_weight, ).ensure_complete().map_err(|_| Error::::XcmExecutionFailed)?; oK(()) @@ -79,7 +108,6 @@ pub mod pallet { fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult { - // TODO: create xcm message let origin_location: MultiLocation = Junction::AccountId32 { network: None, id: sender, @@ -89,14 +117,93 @@ pub mod pallet { origin: origin_location.clone(), dest: MultiLocation, // TODO: extra dest recipient: MultiLocation, // TODO: extra recipient on dest - recipient: MultiLocation, // TODO: extra recipient on dest weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), }; - let mut msg = xcm.create_message()?; + let mut msg = xcm.create_instructions()?; // TODO: execute xcm message - xcm.execute_message(msg)?; + xcm.execute_instructions(msg)?; Ok(()) } } + + impl Pallet { + fn transfer_self_reserve_asset( + assets: MultiAssets, + fee: MultiAsset, + dest: MultiLocation, + recipient: MultiLocation, + dest_weight_limit: WeightLimit, + ) -> Result, DispatchError> { + Ok(Xcm(vec![TransferReserveAsset { + assets: assets.clone(), + dest, + xcm: Xcm(vec![ + Self::buy_execution(fee, &dest, dest_weight_limit)?, + Self::deposit_asset(recipient, assets.len() as u32), + ]), + }])) + } + + fn transfer_to_reserve_asset( + assets: MultiAssets, + fee: MultiAsset, + reserve: MultiLocation, + recipient: MultiLocation, + dest_weight_limit: WeightLimit, + ) -> Result, DispatchError> { + Ok(Xcm(vec![ + WithdrawAsset(assets.clone()), + InitiateReserveWithdraw { + assets: All.into(), + reserve, + xcm: Xcm(vec![ + Self::buy_execution(fee, &reserve, dest_weight_limit)?, + Self::deposit_asset(recipient, assets.len() as u32), + ]), + }, + ])) + } + + fn transfer_to_non_reserve_asset( + assets: MultiAssets, + fee: MultiAsset, + reserve: MultiLocation, + dest: MultiLocation, + recipient: MultiLocation, + dest_weight_limit: WeightLimit, + ) -> Result, DispatchError> { + let mut reanchored_dest = dest; + if reserve == MultiLocation::parent() { + if let MultiLocation { + parents: 1, + interior: X1(Parachain(id)), + } = dest + { + reanchored_dest = Parachain(id).into(); + } + } + + let max_assets = assets.len() as u32; + + Ok(Xcm(vec![ + WithdrawAsset(assets), + InitiateReserveWithdraw { + assets: All.into(), + reserve, + xcm: Xcm(vec![ + Self::buy_execution(half(&fee), &reserve, dest_weight_limit.clone())?, + DepositReserveAsset { + assets: AllCounted(max_assets).into(), + dest: reanchored_dest, + xcm: Xcm(vec![ + Self::buy_execution(half(&fee), &dest, dest_weight_limit)?, + Self::deposit_asset(recipient, max_assets), + ]), + }, + ]), + }, + ])) + } + } } From f094d6b081d9fbcbde5c87f0e2c3118ad321100e Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Tue, 5 Dec 2023 10:49:42 -0500 Subject: [PATCH 08/30] finish the transfer kind logic --- traits/src/lib.rs | 4 ++++ xcm-bridge/src/lib.rs | 23 ++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 1063be88..23a1eecf 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -82,3 +82,7 @@ pub trait Bridge { dest: MultiLocation, ) -> DispatchResult; } + +pub trait AssetReserveLocationParser { + fn reserved_location(asset: &MultiAsset) -> Option; +} \ No newline at end of file diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 597ab513..7e1d6bdf 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -19,6 +19,11 @@ pub mod pallet { type Weigher: WeightBounds; type XcmExecutor: ExecuteXcm; + + #[pallet::constant] + type SelfLocation: Get; + + type ReserveLocationParser: AssetReserveLocationParser; } enum TransferKind { @@ -51,18 +56,22 @@ pub mod pallet { } pub trait XcmHandler { - fn transfer_kind(&self) -> Result, DispatchError>; + fn transfer_kind(&self) -> Result; fn create_instructions(&self) -> Result, DispatchError>; fn execute_instructions(&self, xcm_message: Xcm) -> DispatchResult; } impl XcmHandler for Xcm { /// Get the transfer kind. - fn transfer_kind(&self) -> Result, DispatchError> { - // todo: impl the xcm kind logic, return the following: - // SelfReserveAsset, - // ToReserve, - // ToNonReserve, + fn transfer_kind(&self) -> Result { + let asset_location = T::ReserveLocationParser::reserved_location(&self.asset).ok_or()?; + if asset_location == T::SelfLocation { + TransferKind::SelfReserveAsset + } else if asset_location == self.dest { + TransferKind::ToReserve + } else { + TransferKind::ToNonReserve + } } fn create_instructions(&self) { let kind = Self::transfer_kind(&self)?; @@ -120,7 +129,7 @@ pub mod pallet { weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), }; let mut msg = xcm.create_instructions()?; - // TODO: execute xcm message + xcm.execute_instructions(msg)?; Ok(()) From f2c511790d445d588910bfc4d4529c00a1f62106 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Tue, 5 Dec 2023 10:58:00 -0500 Subject: [PATCH 09/30] minor fix --- xcm-bridge/src/lib.rs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 7e1d6bdf..0014b569 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -24,6 +24,9 @@ pub mod pallet { type SelfLocation: Get; type ReserveLocationParser: AssetReserveLocationParser; + + type MinXcmFee: GetByKey>; + } enum TransferKind { @@ -45,10 +48,12 @@ pub mod pallet { pub enum Error { FailToWeightMessage, XcmExecutionFailed, + MinXcmFeeNotDefined, } struct Xcm { asset: MultiAsset, + fee: MultiAsset, origin: MultiLocation, dest: MultiLocation, recipient: MultiLocation, @@ -73,26 +78,26 @@ pub mod pallet { TransferKind::ToNonReserve } } - fn create_instructions(&self) { - let kind = Self::transfer_kind(&self)?; + fn create_instructions(&self) -> Result, DispatchError> { + let kind = Self::transfer_kind(self)?; let mut xcm_instructions = match kind { - SelfReserveAsset => Self::transfer_self_reserve_asset(assets, fee, dest, recipient, dest_weight_limit)?, - ToReserve => Self::transfer_to_reserve_asset(assets, fee, dest, recipient, dest_weight_limit)?, + SelfReserveAsset => Self::transfer_self_reserve_asset(self.assets, self.fee, self.dest, self.recipient, self.weight)?, + ToReserve => Self::transfer_to_reserve_asset(self.assets, self.fee, self.dest, self.recipient, self.weight)?, ToNonReserve => Self::transfer_to_non_reserve_asset( - assets, - fee, - reserve, - dest, - recipient, - dest_weight_limit, + self.assets, + self.fee, + self.dest, + self.dest.clone(), + self.recipient, + self.weight, )?, }; Ok(xcm_instructions) } - fn execute_instructions(&self, xcm_instructions: Xcm) { + fn execute_instructions(&self, xcm_instructions: Xcm) -> DispatchResult { let message_weight = T::Weigher::weight(xcm_instructions).map_err(|()| Error::::FailToWeightMessage)?; let hash = xcm_instructions.using_encoded(sp_io::hashing::blake2_256); @@ -121,8 +126,11 @@ pub mod pallet { network: None, id: sender, }.into(); + + let min_xcm_fee = T::MinXcmFee::get(&dest).ok_or(Error::::MinXcmFeeNotDefined)?; let xcm = Xcm:: { asset: asset.clone(), + fee: min_xcm_fee, origin: origin_location.clone(), dest: MultiLocation, // TODO: extra dest recipient: MultiLocation, // TODO: extra recipient on dest From 7be8f184cfe5e7ac45df11fd6e32f025be48c7ea Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Fri, 8 Dec 2023 13:44:02 -0500 Subject: [PATCH 10/30] add mock runtime for xcm bridge pallet --- xcm-bridge/src/lib.rs | 18 ++++- xcm-bridge/src/mock.rs | 175 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 xcm-bridge/src/mock.rs diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 0014b569..16d8f0a3 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -4,7 +4,7 @@ pub use self::pallet::*; #[frame_support::pallet] pub mod pallet { - use sygma_traits::Bridge; + use sygma_traits::{Bridge, AssetReserveLocationParser}; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -16,6 +16,9 @@ pub mod pallet { pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// Current pallet index defined in runtime + type PalletIndex: Get; + type Weigher: WeightBounds; type XcmExecutor: ExecuteXcm; @@ -23,8 +26,6 @@ pub mod pallet { #[pallet::constant] type SelfLocation: Get; - type ReserveLocationParser: AssetReserveLocationParser; - type MinXcmFee: GetByKey>; } @@ -69,7 +70,7 @@ pub mod pallet { impl XcmHandler for Xcm { /// Get the transfer kind. fn transfer_kind(&self) -> Result { - let asset_location = T::ReserveLocationParser::reserved_location(&self.asset).ok_or()?; + let asset_location = Pallet::::reserved_location(&self.asset).ok_or()?; if asset_location == T::SelfLocation { TransferKind::SelfReserveAsset } else if asset_location == self.dest { @@ -114,6 +115,15 @@ pub mod pallet { } } + impl AssetReserveLocationParser for Pallet { + fn reserved_location(asset: &MultiAsset) -> Option { + match (&asset.id, &asset.fun) { + (Concrete(id), Fungible(_)) => Some(id.clone()), + _ => None, + } + } + } + #[pallet::call] impl Bridge for Pallet { #[pallet::call_index(0)] diff --git a/xcm-bridge/src/mock.rs b/xcm-bridge/src/mock.rs new file mode 100644 index 00000000..9c805d7d --- /dev/null +++ b/xcm-bridge/src/mock.rs @@ -0,0 +1,175 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +#![cfg(test)] + +use frame_support::{ + pallet_prelude::ConstU32, + parameter_types, + sp_runtime::{ + testing::H256, + traits::{BlakeTwo256, IdentityLookup}, + AccountId32, BuildStorage, Perbill, + }, + traits::{AsEnsureOriginWithArg, ConstU128}, +}; +use frame_system::{self as system, EnsureRoot, EnsureSigned}; + +use crate as basic_fee_handler; + +type Block = frame_system::mocking::MockBlock; + +pub(crate) type Balance = u128; + +pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); + +frame_support::construct_runtime!( + pub enum Test { + System: frame_system, + Assets: pallet_assets::{Pallet, Call, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + } +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + pub const MaxLocks: u32 = 100; + pub const MinimumPeriod: u64 = 1; +} + +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type Block = Block; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId32; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<2>; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 1; +} + +impl pallet_balances::Config for Test { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); + type MaxHolds = (); +} + +parameter_types! { + pub const AssetDeposit: Balance = 1; // 1 Unit deposit to create asset + pub const ApprovalDeposit: Balance = 1; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 1; + pub const MetadataDepositPerByte: Balance = 1; +} + +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = u32; + type AssetIdParameter = codec::Compact; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type RemoveItemsLimit = ConstU32<1000>; + type Freezer = (); + type Extra = (); + type CallbackHandle = (); + type WeightInfo = pallet_assets::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +parameter_types! { + // Make sure put same value with `construct_runtime` + pub const AccessSegregatorPalletIndex: u8 = 3; + pub const FeeHandlerPalletIndex: u8 = 4; + pub RegisteredExtrinsics: Vec<(u8, Vec)> = [ + (AccessSegregatorPalletIndex::get(), b"grant_access".to_vec()), + (FeeHandlerPalletIndex::get(), b"set_fee".to_vec()), + ].to_vec(); +} + +impl xcm_bridge::Config for Test { + type RuntimeEvent = RuntimeEvent; + type PalletIndex = FeeHandlerPalletIndex; + + type Weigher = FixedWeightBounds; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; + + type MinXcmFee = ParachainMinFee; + +} + +parameter_type_with_key! { + pub ParachainMinFee: |location: MultiLocation| -> Option { + #[allow(clippy::match_ref_pats)] // false positive + match (location.parents, location.first_interior()) { + // TODO: mocked parachain id 1000 + (1, Some(Parachain(1000))) => Some(40), + _ => None, + } + }; +} + +parameter_types! { + pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into()))); +} + +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +// Checks events against the latest. A contiguous set of events must be provided. They must +// include the most recent event, but do not have to include every past event. +pub fn assert_events(mut expected: Vec) { + let mut actual: Vec = + system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + + expected.reverse(); + + for evt in expected { + let next = actual.pop().expect("event expected"); + assert_eq!(next, evt, "Events don't match"); + } +} From 73dd70fdcd19f9433abc9c91353d7ba05831ee00 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Mon, 11 Dec 2023 10:36:14 -0500 Subject: [PATCH 11/30] add dest extract logic --- xcm-bridge/src/lib.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 16d8f0a3..0cb3139b 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -50,6 +50,7 @@ pub mod pallet { FailToWeightMessage, XcmExecutionFailed, MinXcmFeeNotDefined, + InvalidDestination, } struct Xcm { @@ -137,13 +138,17 @@ pub mod pallet { id: sender, }.into(); + let (dest_location, recipient) = + Pallet::::extract_dest(&dest).ok_or(Error::::InvalidDestination)?; + let min_xcm_fee = T::MinXcmFee::get(&dest).ok_or(Error::::MinXcmFeeNotDefined)?; + let xcm = Xcm:: { asset: asset.clone(), fee: min_xcm_fee, origin: origin_location.clone(), - dest: MultiLocation, // TODO: extra dest - recipient: MultiLocation, // TODO: extra recipient on dest + dest_location, + recipient, weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), }; let mut msg = xcm.create_instructions()?; @@ -155,6 +160,21 @@ pub mod pallet { } impl Pallet { + pub fn extract_dest(dest: &MultiLocation) -> Option<(MultiLocation, MultiLocation)> { + match (dest.parents, dest.first_interior()) { + // parents must be 1 here because only parents as 1 can be forwarded to xcm bridge logic + // parachains + (1, Some(Parachain(id))) => Some(( + MultiLocation::new(1, X1(Parachain(*id))), + MultiLocation::new(0, dest.interior().clone().split_first().0), + )), + (1, _) => Some(( + MultiLocation::parent(), + MultiLocation::new(0, dest.interior().clone()), + )), + _ => None, + } + } fn transfer_self_reserve_asset( assets: MultiAssets, fee: MultiAsset, From 41d492ecab8cec8fb2efd78a93f11e1a6028b829 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Wed, 13 Dec 2023 13:43:06 -0500 Subject: [PATCH 12/30] runtime fix --- bridge/src/lib.rs | 4 ++- bridge/src/xcm_asset_transactor.rs | 46 +++++++++++++++++------------- traits/src/lib.rs | 4 +-- xcm-bridge/src/lib.rs | 2 ++ 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index f161d1fe..aaaf17bf 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -687,7 +687,9 @@ pub mod pallet { fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult { - &Self::deposit(sender, asset, dest)? + &Self::deposit(sender, Box::from(asset), Box::from(dest))?; + + Ok(()) } } diff --git a/bridge/src/xcm_asset_transactor.rs b/bridge/src/xcm_asset_transactor.rs index 446905f2..2491fcdb 100644 --- a/bridge/src/xcm_asset_transactor.rs +++ b/bridge/src/xcm_asset_transactor.rs @@ -13,9 +13,9 @@ impl XcmResult { - match (who.parents, who.interior) { + match (who.parents, who.first_interior()) { // 1. recipient is the local parachain - (0, None) => { + (0, Some(Parachain(_))) => { // check if the asset is native or foreign, and call the corresponding deposit_asset() if AssetTypeChecker::is_native_asset(what) { CurrencyTransactor::deposit_asset(what, who, context)?; @@ -23,9 +23,30 @@ impl { + // 2. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet + // TODO: this is the sygma multilocation patten + // TODO: the junctions below is just an temporary example, will change it to proper sygma bridge standard, see the link below: + // (https://www.notion.so/chainsafe/Sygma-as-an-Independent-pallet-c481f00ccff84ff49ce917c8b2feacda?pvs=4#6e51e6632e254b9b9a01444ef7297969) + if who.interior == X3(Parachain(1000), GeneralKey{length: 8, data: [1u8; 32]}, GeneralKey {length:8, data: [2u8; 32]}) { + // check if the asset is native or foreign, and deposit the asset to a tmp account first + let tmp_account = MultiLocation::new(0, X1(GeneralKey {length: 8, data: [2u8; 32]})).into_account(); + if AssetTypeChecker::is_native_asset(what) { + CurrencyTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; + } else { + FungiblesTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? + } + + // TODO: call deposit() extrisic in sygmaBrdige pallet. Sygma bridge pallet should also be in the PhantomData type + Forwarder::other_world_transactor_forwarder(tmp_account, what, who).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + + return Ok(()) + } + + // 3. recipient is remote parachain + // recipient is remote parachain // xcm message must have a sender(origin), so a tmp account derived from pallet would be used let tmp_account = MultiLocation::new(0, X1(GeneralKey {length: 8, data: [2u8; 32]})).into_account(); @@ -38,26 +59,11 @@ impl { - // check if the asset is native or foreign, and deposit the asset to a tmp account first - let tmp_account = MultiLocation::new(0, X1(GeneralKey {length: 8, data: [2u8; 32]})).into_account(); - if AssetTypeChecker::is_native_asset(what) { - CurrencyTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; - } else { - FungiblesTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? - } - - // TODO: call deposit() extrisic in sygmaBrdige pallet. Sygma bridge pallet should also be in the PhantomData type - Forwarder::other_world_transactor_forwarder(tmp_account, what.into(), who.into()) + Forwarder::xcm_transactor_forwarder(tmp_account, what, who).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; } // Other destination multilocation not supported, return Err _ => { - Err(XcmError::DestinationUnsupported) + return Err(XcmError::DestinationUnsupported); } } Ok(()) diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 23a1eecf..56504cf7 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -71,8 +71,8 @@ pub trait AssetTypeIdentifier { // TODO: implement these methods pub trait TransactorForwarder { - fn xcm_transactor_forwarder(sender: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult; - fn other_world_transactor_forwarder(sender: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult; + fn xcm_transactor_forwarder(sender: [u8; 32], what: &MultiAsset, who: &MultiLocation) -> DispatchResult; + fn other_world_transactor_forwarder(sender: [u8; 32], what: &MultiAsset, who: &MultiLocation) -> DispatchResult; } pub trait Bridge { diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 0cb3139b..891b8c91 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -1,5 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] +mod mock; + pub use self::pallet::*; #[frame_support::pallet] From de5352208de4fdf817c5fbbb6250ffb94f0a5b77 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Thu, 14 Dec 2023 10:52:32 -0500 Subject: [PATCH 13/30] add tmp account encode logic --- bridge/src/xcm_asset_transactor.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bridge/src/xcm_asset_transactor.rs b/bridge/src/xcm_asset_transactor.rs index 2491fcdb..0b277496 100644 --- a/bridge/src/xcm_asset_transactor.rs +++ b/bridge/src/xcm_asset_transactor.rs @@ -1,4 +1,5 @@ use core::marker::PhantomData; +use codec::Encode; use xcm::latest::{Junction, MultiAsset, MultiLocation, XcmContext}; use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; use xcm::prelude::*; @@ -32,7 +33,7 @@ impl Date: Tue, 2 Jan 2024 16:13:00 -0500 Subject: [PATCH 14/30] runtime fix --- Cargo.lock | 22 +++ bridge-forwarder/src/lib.rs | 27 ++- bridge/Cargo.toml | 2 + bridge/src/lib.rs | 31 ++- bridge/src/mock.rs | 5 +- bridge/src/xcm_asset_transactor.rs | 14 +- traits/src/lib.rs | 5 +- xcm-bridge/Cargo.toml | 8 + xcm-bridge/src/lib.rs | 24 ++- xcm-bridge/src/mock.rs | 306 ++++++++++++++++++----------- 10 files changed, 285 insertions(+), 159 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fbef786a..068440b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1599,6 +1599,22 @@ dependencies = [ "cipher 0.4.4", ] +[[package]] +name = "cumulus-pallet-xcm" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", +] + [[package]] name = "cumulus-primitives-core" version = "0.1.0" @@ -9606,9 +9622,11 @@ dependencies = [ "staging-xcm-executor", "sygma-access-segregator", "sygma-basic-feehandler", + "sygma-bridge-forwarder", "sygma-fee-handler-router", "sygma-percentage-feehandler", "sygma-traits", + "sygma-xcm-bridge", ] [[package]] @@ -9715,6 +9733,9 @@ dependencies = [ name = "sygma-xcm-bridge" version = "0.3.0" dependencies = [ + "cumulus-pallet-xcm", + "cumulus-primitives-core", + "cumulus-primitives-utility", "frame-support", "frame-system", "pallet-assets", @@ -9727,6 +9748,7 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", + "sygma-bridge-forwarder", "sygma-traits", ] diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index 48e2b31b..423b956b 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -1,3 +1,6 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + #![cfg_attr(not(feature = "std"), no_std)] pub use self::pallet::*; @@ -5,11 +8,10 @@ pub use self::pallet::*; #[frame_support::pallet] pub mod pallet { use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::*; - use frame_support::transactional; use frame_support::traits::StorageVersion; - use sygma_traits::{TransactorForwarder, Bridge}; - use xcm::latest::{prelude::*, MultiAsset, MultiLocation}; + use xcm::latest::{MultiAsset, MultiLocation}; + + use sygma_traits::{Bridge, TransactorForwarder}; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -25,26 +27,19 @@ pub mod pallet { } #[pallet::event] - #[pallet::generate_deposit(pub(super) fn deposit_event)] + #[pallet::generate_deposit(pub (super) fn deposit_event)] pub enum Event { XCMTransferForward {}, OtherWorldTransferForward {}, } - #[pallet::call] impl TransactorForwarder for Pallet { - #[pallet::call_index(0)] - #[pallet::weight(Weight::from_parts(195_000_000, 0))] - #[transactional] - fn xcm_transactor_forwarder(origin: OriginFor, what: MultiAsset, who: MultiLocation) -> DispatchResult { - T::XCMBridge::transfer(origin.into(), what, who)?; + fn xcm_transactor_forwarder(origin: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult { + T::XCMBridge::transfer(origin, what, who) } - #[pallet::call_index(1)] - #[pallet::weight(Weight::from_parts(195_000_000, 0))] - #[transactional] - fn other_world_transactor_forwarder(origin: OriginFor, what: MultiAsset, who: MultiLocation) -> DispatchResult { - T::SygmaBridge::transfer(origin.into(), what, who)? + fn other_world_transactor_forwarder(origin: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult { + T::SygmaBridge::transfer(origin, what, who) } } } diff --git a/bridge/Cargo.toml b/bridge/Cargo.toml index 87b6d997..c1c716da 100644 --- a/bridge/Cargo.toml +++ b/bridge/Cargo.toml @@ -39,6 +39,8 @@ sygma-access-segregator = { path = "../access-segregator", default-features = fa sygma-basic-feehandler = { path = "../basic-fee-handler", default-features = false } sygma-percentage-feehandler = { path = "../percentage-fee-handler", default-features = false } sygma-fee-handler-router = { path = "../fee-handler-router", default-features = false } +sygma-bridge-forwarder = { path = "../bridge-forwarder", default-features = false } +sygma-xcm-bridge = { path = "../xcm-bridge", default-features = false } [dev-dependencies] assert_matches = "1.4.0" diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index aaaf17bf..ad5058fb 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -34,7 +34,7 @@ pub mod pallet { traits::{ContainsPair, StorageVersion}, transactional, PalletId, }; - + use frame_support::dispatch::RawOrigin; use frame_system::pallet_prelude::*; use primitive_types::U256; use scale_info::TypeInfo; @@ -49,10 +49,7 @@ pub mod pallet { use crate::eip712; use sp_std::collections::btree_map::BTreeMap; - use sygma_traits::{ - ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, - MpcAddress, ResourceId, TransferType, VerifyingContractAddress, Bridge, - }; + use sygma_traits::{ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, MpcAddress, ResourceId, TransferType, VerifyingContractAddress, Bridge, AssetTypeIdentifier}; #[allow(dead_code)] const LOG_TARGET: &str = "runtime::sygmabridge"; @@ -683,11 +680,31 @@ pub mod pallet { } } - impl Bridge for Pallet { + impl AssetTypeIdentifier for Pallet { + fn is_native_asset(asset: &MultiAsset) -> bool { + let native_locations = [ + MultiLocation::here(), + MultiLocation::new(1, X1(Parachain(T::get().into()))), + ]; + + match (&asset.id, &asset.fun) { + (Concrete(ref id), Fungible(_)) => { + native_locations.contains(id) + }, + _ => false, + } + } + } + + + impl Bridge for Pallet where + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, + { fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult { - &Self::deposit(sender, Box::from(asset), Box::from(dest))?; + let sender_origin = OriginFor::::from(RawOrigin::Signed(sender.into())); + Pallet::::deposit(sender_origin, Box::from(asset), Box::from(dest))?; Ok(()) } diff --git a/bridge/src/mock.rs b/bridge/src/mock.rs index f149ed87..ce172c9a 100644 --- a/bridge/src/mock.rs +++ b/bridge/src/mock.rs @@ -31,6 +31,7 @@ use xcm_builder::{ SiblingParachainConvertsVia, }; use xcm_executor::traits::{Error as ExecutionError, MatchesFungibles}; +use crate::xcm_asset_transactor::XCMAssetTransactor; type Block = frame_system::mocking::MockBlock; @@ -47,6 +48,8 @@ frame_support::construct_runtime!( SygmaBridge: sygma_bridge::{Pallet, Call, Storage, Event} = 6, SygmaPercentageFeeHandler: sygma_percentage_feehandler::{Pallet, Call, Storage, Event} = 7, SygmaFeeHandlerRouter: sygma_fee_handler_router::{Pallet, Call, Storage, Event} = 8, + SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Call, Storage, Event} = 9, + SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Call, Storage, Event} = 10, } ); @@ -482,7 +485,7 @@ impl sygma_bridge::Config for Runtime { type EIP712ChainID = EIP712ChainID; type DestVerifyingContractAddress = DestVerifyingContractAddress; type FeeHandler = SygmaFeeHandlerRouter; - type AssetTransactor = AssetTransactors; + type AssetTransactor = XCMAssetTransactor; type ResourcePairs = ResourcePairs; type IsReserve = ReserveChecker; type ExtractDestData = DestinationDataParser; diff --git a/bridge/src/xcm_asset_transactor.rs b/bridge/src/xcm_asset_transactor.rs index 0b277496..18f81baa 100644 --- a/bridge/src/xcm_asset_transactor.rs +++ b/bridge/src/xcm_asset_transactor.rs @@ -28,20 +28,20 @@ impl { // 2. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet - // TODO: this is the sygma multilocation patten + // TODO: this is the sygma multilocation pattern // TODO: the junctions below is just an temporary example, will change it to proper sygma bridge standard, see the link below: // (https://www.notion.so/chainsafe/Sygma-as-an-Independent-pallet-c481f00ccff84ff49ce917c8b2feacda?pvs=4#6e51e6632e254b9b9a01444ef7297969) if who.interior == X3(Parachain(1000), GeneralKey{length: 8, data: [1u8; 32]}, GeneralKey {length:8, data: [2u8; 32]}) { // check if the asset is native or foreign, and deposit the asset to a tmp account first let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey {length: 8, data: [2u8; 32]})).encode()); if AssetTypeChecker::is_native_asset(what) { - CurrencyTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; + CurrencyTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; } else { - FungiblesTransactor::deposit_asset(what, &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? + FungiblesTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? } // TODO: call deposit() extrisic in sygmaBrdige pallet. Sygma bridge pallet should also be in the PhantomData type - Forwarder::other_world_transactor_forwarder(tmp_account, what, who).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + Forwarder::other_world_transactor_forwarder(tmp_account, what.clone(), *who).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; return Ok(()) } @@ -54,13 +54,13 @@ impl { diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 56504cf7..2000539a 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -69,10 +69,9 @@ pub trait AssetTypeIdentifier { fn is_native_asset(asset: &MultiAsset) -> bool; } -// TODO: implement these methods pub trait TransactorForwarder { - fn xcm_transactor_forwarder(sender: [u8; 32], what: &MultiAsset, who: &MultiLocation) -> DispatchResult; - fn other_world_transactor_forwarder(sender: [u8; 32], what: &MultiAsset, who: &MultiLocation) -> DispatchResult; + fn xcm_transactor_forwarder(sender: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult; + fn other_world_transactor_forwarder(sender: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult; } pub trait Bridge { diff --git a/xcm-bridge/Cargo.toml b/xcm-bridge/Cargo.toml index 28bb014e..7d52b2be 100644 --- a/xcm-bridge/Cargo.toml +++ b/xcm-bridge/Cargo.toml @@ -12,14 +12,22 @@ scale-info = { version = "2.5.0", default-features = false, features = ["derive" frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } # Polkadot xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +# Cumulus +cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } + # Local sygma-traits = { path = "../traits", default-features = false } +sygma-bridge-forwarder = { path = "../bridge-forwarder", default-features = false } [dev-dependencies] # Substrate diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 891b8c91..1e8849bd 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -6,7 +6,14 @@ pub use self::pallet::*; #[frame_support::pallet] pub mod pallet { - use sygma_traits::{Bridge, AssetReserveLocationParser}; + use sygma_traits::{Bridge, AssetReserveLocationParser, AssetTypeIdentifier}; + use frame_support::{ + dispatch::DispatchResult, + pallet_prelude::*, + traits::{ContainsPair, StorageVersion}, + }; + use xcm::latest::{prelude::*, MultiLocation, Weight as XCMWeight}; + use xcm_executor::traits::WeightBounds; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -27,9 +34,6 @@ pub mod pallet { #[pallet::constant] type SelfLocation: Get; - - type MinXcmFee: GetByKey>; - } enum TransferKind { @@ -51,7 +55,6 @@ pub mod pallet { pub enum Error { FailToWeightMessage, XcmExecutionFailed, - MinXcmFeeNotDefined, InvalidDestination, } @@ -70,7 +73,7 @@ pub mod pallet { fn execute_instructions(&self, xcm_message: Xcm) -> DispatchResult; } - impl XcmHandler for Xcm { + impl XcmHandler for Xcm { /// Get the transfer kind. fn transfer_kind(&self) -> Result { let asset_location = Pallet::::reserved_location(&self.asset).ok_or()?; @@ -118,6 +121,7 @@ pub mod pallet { } } + impl AssetReserveLocationParser for Pallet { fn reserved_location(asset: &MultiAsset) -> Option { match (&asset.id, &asset.fun) { @@ -127,11 +131,7 @@ pub mod pallet { } } - #[pallet::call] impl Bridge for Pallet { - #[pallet::call_index(0)] - #[pallet::weight(Weight::from_parts(195_000_000, 0))] - #[transactional] fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult { @@ -143,11 +143,9 @@ pub mod pallet { let (dest_location, recipient) = Pallet::::extract_dest(&dest).ok_or(Error::::InvalidDestination)?; - let min_xcm_fee = T::MinXcmFee::get(&dest).ok_or(Error::::MinXcmFeeNotDefined)?; - let xcm = Xcm:: { asset: asset.clone(), - fee: min_xcm_fee, + fee: asset.clone(), // TODO: fee is asset? origin: origin_location.clone(), dest_location, recipient, diff --git a/xcm-bridge/src/mock.rs b/xcm-bridge/src/mock.rs index 9c805d7d..1cc3d655 100644 --- a/xcm-bridge/src/mock.rs +++ b/xcm-bridge/src/mock.rs @@ -3,31 +3,32 @@ #![cfg(test)] -use frame_support::{ - pallet_prelude::ConstU32, - parameter_types, - sp_runtime::{ - testing::H256, - traits::{BlakeTwo256, IdentityLookup}, - AccountId32, BuildStorage, Perbill, - }, - traits::{AsEnsureOriginWithArg, ConstU128}, -}; -use frame_system::{self as system, EnsureRoot, EnsureSigned}; - -use crate as basic_fee_handler; - -type Block = frame_system::mocking::MockBlock; +use frame_support::{construct_runtime, pallet_prelude::ConstU32, parameter_types, sp_runtime::{ + AccountId32, + BuildStorage, + Perbill, testing::H256, traits::{BlakeTwo256, IdentityLookup}, +}, traits::{AsEnsureOriginWithArg, ConstU128, Everything, Nothing}}; +use frame_system::{EnsureSigned, self as system}; +use xcm::latest::{prelude::*, Weight as XCMWeight}; +use xcm_builder::{AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit}; +use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; + +use sygma_bridge::XCMAssetTransactor; + +type Block = frame_system::mocking::MockBlock; pub(crate) type Balance = u128; pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); -frame_support::construct_runtime!( - pub enum Test { +construct_runtime! ( + pub enum Runtime { System: frame_system, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, Assets: pallet_assets::{Pallet, Call, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Storage, Event} = 5, + SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Call, Storage, Event}, } ); @@ -39,50 +40,58 @@ parameter_types! { pub const MinimumPeriod: u64 = 1; } -impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type Block = Block; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId32; - type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<2>; +parameter_types! { + // Make sure put same value with `construct_runtime` + pub const XcmBridgePalletIndex: u8 = 6; + pub RegisteredExtrinsics: Vec<(u8, Vec)> = [ + (XcmBridgePalletIndex::get(), b"transfer".to_vec()), + ].to_vec(); +} + +impl frame_system::Config for Runtime { + type BaseCallFilter = frame_support::traits::Everything; + type Block = Block; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId32; + type Lookup = IdentityLookup; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<2>; } parameter_types! { pub const ExistentialDeposit: Balance = 1; } -impl pallet_balances::Config for Test { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type FreezeIdentifier = (); - type MaxFreezes = (); - type RuntimeHoldReason = (); - type MaxHolds = (); +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); + type MaxHolds = (); } parameter_types! { @@ -93,83 +102,156 @@ parameter_types! { pub const MetadataDepositPerByte: Balance = 1; } -impl pallet_assets::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type AssetId = u32; - type AssetIdParameter = codec::Compact; - type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = AssetDeposit; - type AssetAccountDeposit = ConstU128<10>; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = AssetsStringLimit; - type RemoveItemsLimit = ConstU32<1000>; - type Freezer = (); - type Extra = (); - type CallbackHandle = (); - type WeightInfo = pallet_assets::weights::SubstrateWeight; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = u32; + type AssetIdParameter = codec::Compact; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type RemoveItemsLimit = ConstU32<1000>; + type Freezer = (); + type Extra = (); + type CallbackHandle = (); + type WeightInfo = pallet_assets::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } -parameter_types! { - // Make sure put same value with `construct_runtime` - pub const AccessSegregatorPalletIndex: u8 = 3; - pub const FeeHandlerPalletIndex: u8 = 4; - pub RegisteredExtrinsics: Vec<(u8, Vec)> = [ - (AccessSegregatorPalletIndex::get(), b"grant_access".to_vec()), - (FeeHandlerPalletIndex::get(), b"set_fee".to_vec()), - ].to_vec(); +impl xcm_bridge::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PalletIndex = XcmBridgePalletIndex; + + type Weigher = FixedWeightBounds; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; } -impl xcm_bridge::Config for Test { - type RuntimeEvent = RuntimeEvent; - type PalletIndex = FeeHandlerPalletIndex; +pub struct XcmConfig; - type Weigher = FixedWeightBounds; - type XcmExecutor = XcmExecutor; - type SelfLocation = SelfLocation; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = XCMAssetTransactor< + CurrencyTransactor, + FungiblesTransactor, + SygmaXcmBridge, + SygmaBridgeForwarder, + >; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = NativeAsset; + type IsTeleporter = (); + type UniversalLocation = SelfLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = DynamicWeightTrader< + WeightPerSecond, + ::AssetId, + AssetsRegistry, + helper::XTransferTakeRevenue, + >; + type ResponseHandler = (); + type AssetTrap = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = ConstU32<64>; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = WithOriginFilter; + type SafeCallFilter = Everything; + type Aliasers = (); +} - type MinXcmFee = ParachainMinFee; +// TODO: add xcm simulator +pub type XcmRouter = ParachainXcmRouter; -} +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + AllowUnpaidExecutionFrom, +); + +pub type LocationToAccountId = ( + ParentIsPreset, + SiblingParachainConvertsVia, + AccountId32Aliases, +); -parameter_type_with_key! { - pub ParachainMinFee: |location: MultiLocation| -> Option { - #[allow(clippy::match_ref_pats)] // false positive - match (location.parents, location.first_interior()) { - // TODO: mocked parachain id 1000 - (1, Some(Parachain(1000))) => Some(40), - _ => None, - } - }; +pub type XcmOriginToTransactDispatchOrigin = ( + SovereignSignedViaLocation, + RelayChainAsNative, + SiblingParachainAsNative, + SignedAccountId32AsNative, +); + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Rococo; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UnitWeightCost: XCMWeight = 1u64.into(); + pub const MaxInstructions: u32 = 100; } +pub type CurrencyTransactor = CurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId32, + // We don't track any teleports of `Balances`. + (), +>; + +/// Means for transacting assets besides the native currency on this chain. +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + sygma_bridge::SimpleForeignAssetConverter, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId32, + // Disable teleport. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; + parameter_types! { pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into()))); } pub fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext } // Checks events against the latest. A contiguous set of events must be provided. They must // include the most recent event, but do not have to include every past event. pub fn assert_events(mut expected: Vec) { - let mut actual: Vec = - system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + let mut actual: Vec = + system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); - expected.reverse(); + expected.reverse(); - for evt in expected { - let next = actual.pop().expect("event expected"); - assert_eq!(next, evt, "Events don't match"); - } + for evt in expected { + let next = actual.pop().expect("event expected"); + assert_eq!(next, evt, "Events don't match"); + } } From aa4ff9b16dacb25fad36e66a1439a7ad42a075b1 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Wed, 3 Jan 2024 14:03:08 -0500 Subject: [PATCH 15/30] fix the compile errors in xcm bridge --- Cargo.lock | 1 + bridge/Cargo.toml | 3 + bridge/src/lib.rs | 4874 +++++++++++++++++++++-------------------- xcm-bridge/Cargo.toml | 2 + xcm-bridge/src/lib.rs | 116 +- 5 files changed, 2530 insertions(+), 2466 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 068440b2..4a756821 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9595,6 +9595,7 @@ dependencies = [ "arrayref", "assert_matches", "bounded-collections", + "cumulus-primitives-core", "ethabi", "fixed", "frame-benchmarking", diff --git a/bridge/Cargo.toml b/bridge/Cargo.toml index c1c716da..f5658dba 100644 --- a/bridge/Cargo.toml +++ b/bridge/Cargo.toml @@ -34,6 +34,9 @@ xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-s xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +# Cumulus +cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } + sygma-traits = { path = "../traits", default-features = false } sygma-access-segregator = { path = "../access-segregator", default-features = false } sygma-basic-feehandler = { path = "../basic-fee-handler", default-features = false } diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index ad5058fb..bd490458 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -3,17 +3,18 @@ #![cfg_attr(not(feature = "std"), no_std)] -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; -pub mod migration; -pub mod weights; -pub use weights::*; - #[macro_use] extern crate arrayref; +pub use weights::*; + pub use self::pallet::*; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod migration; +pub mod weights; + mod eip712; mod encode; @@ -25,266 +26,268 @@ mod xcm_asset_transactor; #[allow(clippy::large_enum_variant)] #[frame_support::pallet] pub mod pallet { - use crate::encode::{abi::encode_packed, SolidityDataType}; - use codec::{Decode, Encode}; - use ethabi::{encode as abi_encode, token::Token}; - use frame_support::{ - dispatch::DispatchResult, - pallet_prelude::*, - traits::{ContainsPair, StorageVersion}, - transactional, PalletId, - }; - use frame_support::dispatch::RawOrigin; - use frame_system::pallet_prelude::*; - use primitive_types::U256; - use scale_info::TypeInfo; - use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; - use sp_runtime::{ - traits::{AccountIdConversion, Clear}, - RuntimeDebug, - }; - use sp_std::{boxed::Box, convert::From, vec, vec::Vec}; - use xcm::latest::{prelude::*, MultiLocation}; - use xcm_executor::traits::TransactAsset; - - use crate::eip712; - use sp_std::collections::btree_map::BTreeMap; - use sygma_traits::{ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, MpcAddress, ResourceId, TransferType, VerifyingContractAddress, Bridge, AssetTypeIdentifier}; - - #[allow(dead_code)] - const LOG_TARGET: &str = "runtime::sygmabridge"; - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); - - #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] - pub struct Proposal { - pub origin_domain_id: DomainID, - pub deposit_nonce: DepositNonce, - pub resource_id: ResourceId, - pub data: Vec, - } - - pub trait WeightInfo { - fn pause_bridge() -> Weight; - fn unpause_bridge() -> Weight; - fn set_mpc_address() -> Weight; - fn register_domain() -> Weight; - fn unregister_domain() -> Weight; - fn deposit() -> Weight; - fn retry() -> Weight; - fn execute_proposal(n: u32) -> Weight; - fn pause_all_bridges() -> Weight; - fn unpause_all_bridges() -> Weight; - } - - #[pallet::pallet] - #[pallet::storage_version(STORAGE_VERSION)] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config + sygma_access_segregator::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// Bridge transfer reserve accounts mapping with designated assets - #[pallet::constant] - type TransferReserveAccounts: Get>; - - /// EIP712 Verifying contract address - /// This is used in EIP712 typed data domain - #[pallet::constant] - type DestVerifyingContractAddress: Get; - - /// Pallet ChainID - /// This is used in EIP712 typed data domain - #[pallet::constant] - type EIP712ChainID: Get; - - /// Fee reserve account - #[pallet::constant] - type FeeReserveAccount: Get; - - /// Fee information getter - type FeeHandler: FeeHandler; - - /// Implementation of withdraw and deposit an asset. - type AssetTransactor: TransactAsset; - - /// AssetId and ResourceId pairs - type ResourcePairs: Get>; - - /// Return true if asset reserved on current chain - type IsReserve: ContainsPair; - - /// Extract dest data from given MultiLocation - type ExtractDestData: ExtractDestinationData; - - /// Config ID for the current pallet instance - type PalletId: Get; - - /// Current pallet index defined in runtime - type PalletIndex: Get; - - /// Asset decimal converter - type DecimalConverter: DecimalConverter; - - /// Type representing the weight of this pallet - type WeightInfo: WeightInfo; - } - - #[allow(dead_code)] - #[pallet::event] - #[pallet::generate_deposit(pub (super) fn deposit_event)] - pub enum Event { - /// When initial bridge transfer send to dest domain - /// args: [dest_domain_id, resource_id, deposit_nonce, sender, transfer_type, - /// deposit_data, handler_response, ] - Deposit { - dest_domain_id: DomainID, - resource_id: ResourceId, - deposit_nonce: DepositNonce, - sender: T::AccountId, - transfer_type: TransferType, - deposit_data: Vec, - handler_response: Vec, - }, - /// When proposal was executed successfully - ProposalExecution { - origin_domain_id: DomainID, - deposit_nonce: DepositNonce, - data_hash: [u8; 32], - }, - /// When proposal was faild to execute - FailedHandlerExecution { - error: Vec, - origin_domain_id: DomainID, - deposit_nonce: DepositNonce, - }, - /// When user is going to retry a bridge transfer - /// args: [deposit_on_block_height, dest_domain_id, sender] - Retry { deposit_on_block_height: u128, dest_domain_id: DomainID, sender: T::AccountId }, - /// When bridge is paused - /// args: [dest_domain_id] - BridgePaused { dest_domain_id: DomainID }, - /// When bridge is unpaused - /// args: [dest_domain_id] - BridgeUnpaused { dest_domain_id: DomainID }, - /// When registering a new dest domainID with its corresponding chainID - RegisterDestDomain { sender: T::AccountId, domain_id: DomainID, chain_id: ChainID }, - /// When unregistering a dest domainID with its corresponding chainID - UnregisterDestDomain { sender: T::AccountId, domain_id: DomainID, chain_id: ChainID }, - /// When bridge fee is collected - FeeCollected { - fee_payer: T::AccountId, - dest_domain_id: DomainID, - resource_id: ResourceId, - fee_amount: u128, - fee_asset_id: AssetId, - }, - /// When all bridges are paused - AllBridgePaused { sender: T::AccountId }, - /// When all bridges are unpaused - AllBridgeUnpaused { sender: T::AccountId }, - } - - #[pallet::error] - pub enum Error { - /// Account has not gained access permission - AccessDenied, - /// Protected operation, must be performed by relayer - BadMpcSignature, - /// Insufficient balance on sender account - InsufficientBalance, - /// Asset transactor execution failed - TransactFailed, - /// The withdrawn amount can not cover the fee payment - FeeTooExpensive, - /// MPC address not set - MissingMpcAddress, - /// MPC address can not be updated - MpcAddrNotUpdatable, - /// Bridge is paused - BridgePaused, - /// Bridge is unpaused - BridgeUnpaused, - /// Fee config option missing - MissingFeeConfig, - /// Asset not bound to a resource id - AssetNotBound, - /// Proposal has either failed or succeeded - ProposalAlreadyComplete, - /// Proposal list empty - EmptyProposalList, - /// Transactor operation failed - TransactorFailed, - /// Deposit data not correct - InvalidDepositData, - /// Dest domain not supported - DestDomainNotSupported, - /// Dest chain id not match - DestChainIDNotMatch, - /// Failed to extract destination data - ExtractDestDataFailed, - /// Failed on the decimal converter - DecimalConversionFail, - /// Deposit nonce has reached max integer value - DepositNonceOverflow, - /// Asset not bound to a liquidity holder account - NoLiquidityHolderAccountBound, - /// Function unimplemented - Unimplemented, - } - - /// Deposit counter of dest domain - #[pallet::storage] - #[pallet::getter(fn deposit_counts)] - pub type DepositCounts = StorageMap<_, Twox64Concat, DomainID, DepositNonce, ValueQuery>; - - /// Bridge Pause indicator - /// Bridge is unpaused initially, until pause - /// After mpc address setup, bridge should be paused until ready to unpause - #[pallet::storage] - #[pallet::getter(fn is_paused)] - pub type IsPaused = StorageMap<_, Twox64Concat, DomainID, bool, ValueQuery>; - - /// Pre-set MPC address - #[pallet::storage] - #[pallet::getter(fn mpc_addr)] - pub type MpcAddr = StorageValue<_, MpcAddress, ValueQuery>; - - /// Mark whether a deposit nonce was used. Used to mark execution status of a proposal. - #[pallet::storage] - #[pallet::getter(fn used_nonces)] - pub type UsedNonces = StorageDoubleMap< - _, - Twox64Concat, - DomainID, - Twox64Concat, - DepositNonce, - DepositNonce, - ValueQuery, - >; - - /// Mark supported dest domainID - #[pallet::storage] - #[pallet::getter(fn dest_domain_ids)] - pub type DestDomainIds = StorageMap<_, Twox64Concat, DomainID, bool, ValueQuery>; - - /// Mark the pairs for supported dest domainID with its corresponding chainID - /// The chainID is not directly used in pallet, this map is designed more about rechecking the - /// domainID - #[pallet::storage] - #[pallet::getter(fn dest_chain_ids)] - pub type DestChainIds = StorageMap<_, Twox64Concat, DomainID, ChainID>; - - #[pallet::call] - impl Pallet - where - ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, - { - /// Pause bridge, this would lead to bridge transfer failure before it being unpaused. - #[pallet::call_index(0)] - #[pallet::weight(::WeightInfo::pause_bridge())] - pub fn pause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { - ensure!( + use codec::{Decode, Encode}; + use cumulus_primitives_core::ParaId; + use ethabi::{encode as abi_encode, token::Token}; + use frame_support::{ + dispatch::DispatchResult, + pallet_prelude::*, + PalletId, + traits::{ContainsPair, StorageVersion}, transactional, + }; + use frame_support::dispatch::RawOrigin; + use frame_system::pallet_prelude::*; + use primitive_types::U256; + use scale_info::TypeInfo; + use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; + use sp_runtime::{ + RuntimeDebug, + traits::{AccountIdConversion, Clear}, + }; + use sp_std::{boxed::Box, convert::From, vec, vec::Vec}; + use sp_std::collections::btree_map::BTreeMap; + use xcm::latest::{MultiLocation, prelude::*}; + use xcm_executor::traits::TransactAsset; + + use sygma_traits::{AssetTypeIdentifier, Bridge, ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, MpcAddress, ResourceId, TransferType, VerifyingContractAddress}; + + use crate::eip712; + use crate::encode::{abi::encode_packed, SolidityDataType}; + + #[allow(dead_code)] + const LOG_TARGET: &str = "runtime::sygmabridge"; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] + pub struct Proposal { + pub origin_domain_id: DomainID, + pub deposit_nonce: DepositNonce, + pub resource_id: ResourceId, + pub data: Vec, + } + + pub trait WeightInfo { + fn pause_bridge() -> Weight; + fn unpause_bridge() -> Weight; + fn set_mpc_address() -> Weight; + fn register_domain() -> Weight; + fn unregister_domain() -> Weight; + fn deposit() -> Weight; + fn retry() -> Weight; + fn execute_proposal(n: u32) -> Weight; + fn pause_all_bridges() -> Weight; + fn unpause_all_bridges() -> Weight; + } + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + sygma_access_segregator::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Bridge transfer reserve accounts mapping with designated assets + #[pallet::constant] + type TransferReserveAccounts: Get>; + + /// EIP712 Verifying contract address + /// This is used in EIP712 typed data domain + #[pallet::constant] + type DestVerifyingContractAddress: Get; + + /// Pallet ChainID + /// This is used in EIP712 typed data domain + #[pallet::constant] + type EIP712ChainID: Get; + + /// Fee reserve account + #[pallet::constant] + type FeeReserveAccount: Get; + + /// Fee information getter + type FeeHandler: FeeHandler; + + /// Implementation of withdraw and deposit an asset. + type AssetTransactor: TransactAsset; + + /// AssetId and ResourceId pairs + type ResourcePairs: Get>; + + /// Return true if asset reserved on current chain + type IsReserve: ContainsPair; + + /// Extract dest data from given MultiLocation + type ExtractDestData: ExtractDestinationData; + + /// Config ID for the current pallet instance + type PalletId: Get; + + /// Current pallet index defined in runtime + type PalletIndex: Get; + + /// Asset decimal converter + type DecimalConverter: DecimalConverter; + + /// Type representing the weight of this pallet + type WeightInfo: WeightInfo; + } + + #[allow(dead_code)] + #[pallet::event] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + /// When initial bridge transfer send to dest domain + /// args: [dest_domain_id, resource_id, deposit_nonce, sender, transfer_type, + /// deposit_data, handler_response, ] + Deposit { + dest_domain_id: DomainID, + resource_id: ResourceId, + deposit_nonce: DepositNonce, + sender: T::AccountId, + transfer_type: TransferType, + deposit_data: Vec, + handler_response: Vec, + }, + /// When proposal was executed successfully + ProposalExecution { + origin_domain_id: DomainID, + deposit_nonce: DepositNonce, + data_hash: [u8; 32], + }, + /// When proposal was faild to execute + FailedHandlerExecution { + error: Vec, + origin_domain_id: DomainID, + deposit_nonce: DepositNonce, + }, + /// When user is going to retry a bridge transfer + /// args: [deposit_on_block_height, dest_domain_id, sender] + Retry { deposit_on_block_height: u128, dest_domain_id: DomainID, sender: T::AccountId }, + /// When bridge is paused + /// args: [dest_domain_id] + BridgePaused { dest_domain_id: DomainID }, + /// When bridge is unpaused + /// args: [dest_domain_id] + BridgeUnpaused { dest_domain_id: DomainID }, + /// When registering a new dest domainID with its corresponding chainID + RegisterDestDomain { sender: T::AccountId, domain_id: DomainID, chain_id: ChainID }, + /// When unregistering a dest domainID with its corresponding chainID + UnregisterDestDomain { sender: T::AccountId, domain_id: DomainID, chain_id: ChainID }, + /// When bridge fee is collected + FeeCollected { + fee_payer: T::AccountId, + dest_domain_id: DomainID, + resource_id: ResourceId, + fee_amount: u128, + fee_asset_id: AssetId, + }, + /// When all bridges are paused + AllBridgePaused { sender: T::AccountId }, + /// When all bridges are unpaused + AllBridgeUnpaused { sender: T::AccountId }, + } + + #[pallet::error] + pub enum Error { + /// Account has not gained access permission + AccessDenied, + /// Protected operation, must be performed by relayer + BadMpcSignature, + /// Insufficient balance on sender account + InsufficientBalance, + /// Asset transactor execution failed + TransactFailed, + /// The withdrawn amount can not cover the fee payment + FeeTooExpensive, + /// MPC address not set + MissingMpcAddress, + /// MPC address can not be updated + MpcAddrNotUpdatable, + /// Bridge is paused + BridgePaused, + /// Bridge is unpaused + BridgeUnpaused, + /// Fee config option missing + MissingFeeConfig, + /// Asset not bound to a resource id + AssetNotBound, + /// Proposal has either failed or succeeded + ProposalAlreadyComplete, + /// Proposal list empty + EmptyProposalList, + /// Transactor operation failed + TransactorFailed, + /// Deposit data not correct + InvalidDepositData, + /// Dest domain not supported + DestDomainNotSupported, + /// Dest chain id not match + DestChainIDNotMatch, + /// Failed to extract destination data + ExtractDestDataFailed, + /// Failed on the decimal converter + DecimalConversionFail, + /// Deposit nonce has reached max integer value + DepositNonceOverflow, + /// Asset not bound to a liquidity holder account + NoLiquidityHolderAccountBound, + /// Function unimplemented + Unimplemented, + } + + /// Deposit counter of dest domain + #[pallet::storage] + #[pallet::getter(fn deposit_counts)] + pub type DepositCounts = StorageMap<_, Twox64Concat, DomainID, DepositNonce, ValueQuery>; + + /// Bridge Pause indicator + /// Bridge is unpaused initially, until pause + /// After mpc address setup, bridge should be paused until ready to unpause + #[pallet::storage] + #[pallet::getter(fn is_paused)] + pub type IsPaused = StorageMap<_, Twox64Concat, DomainID, bool, ValueQuery>; + + /// Pre-set MPC address + #[pallet::storage] + #[pallet::getter(fn mpc_addr)] + pub type MpcAddr = StorageValue<_, MpcAddress, ValueQuery>; + + /// Mark whether a deposit nonce was used. Used to mark execution status of a proposal. + #[pallet::storage] + #[pallet::getter(fn used_nonces)] + pub type UsedNonces = StorageDoubleMap< + _, + Twox64Concat, + DomainID, + Twox64Concat, + DepositNonce, + DepositNonce, + ValueQuery, + >; + + /// Mark supported dest domainID + #[pallet::storage] + #[pallet::getter(fn dest_domain_ids)] + pub type DestDomainIds = StorageMap<_, Twox64Concat, DomainID, bool, ValueQuery>; + + /// Mark the pairs for supported dest domainID with its corresponding chainID + /// The chainID is not directly used in pallet, this map is designed more about rechecking the + /// domainID + #[pallet::storage] + #[pallet::getter(fn dest_chain_ids)] + pub type DestChainIds = StorageMap<_, Twox64Concat, DomainID, ChainID>; + + #[pallet::call] + impl Pallet + where + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, + { + /// Pause bridge, this would lead to bridge transfer failure before it being unpaused. + #[pallet::call_index(0)] + #[pallet::weight(< T as Config >::WeightInfo::pause_bridge())] + pub fn pause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"pause_bridge".to_vec(), @@ -292,21 +295,21 @@ pub mod pallet { ), Error::::AccessDenied ); - ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); + ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); - // Mark as paused - IsPaused::::insert(dest_domain_id, true); + // Mark as paused + IsPaused::::insert(dest_domain_id, true); - // Emit BridgePause event - Self::deposit_event(Event::BridgePaused { dest_domain_id }); - Ok(()) - } + // Emit BridgePause event + Self::deposit_event(Event::BridgePaused { dest_domain_id }); + Ok(()) + } - /// Unpause bridge. - #[pallet::call_index(1)] - #[pallet::weight(::WeightInfo::unpause_bridge())] - pub fn unpause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { - ensure!( + /// Unpause bridge. + #[pallet::call_index(1)] + #[pallet::weight(< T as Config >::WeightInfo::unpause_bridge())] + pub fn unpause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"unpause_bridge".to_vec(), @@ -314,24 +317,24 @@ pub mod pallet { ), Error::::AccessDenied ); - ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); + ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); - // make sure the current status is paused - ensure!(IsPaused::::get(dest_domain_id), Error::::BridgeUnpaused); + // make sure the current status is paused + ensure!(IsPaused::::get(dest_domain_id), Error::::BridgeUnpaused); - // Mark as unpaused - IsPaused::::insert(dest_domain_id, false); + // Mark as unpaused + IsPaused::::insert(dest_domain_id, false); - // Emit BridgeUnpause event - Self::deposit_event(Event::BridgeUnpaused { dest_domain_id }); - Ok(()) - } + // Emit BridgeUnpause event + Self::deposit_event(Event::BridgeUnpaused { dest_domain_id }); + Ok(()) + } - /// Mark an ECDSA address as a MPC account. - #[pallet::call_index(2)] - #[pallet::weight(::WeightInfo::set_mpc_address())] - pub fn set_mpc_address(origin: OriginFor, addr: MpcAddress) -> DispatchResult { - ensure!( + /// Mark an ECDSA address as a MPC account. + #[pallet::call_index(2)] + #[pallet::weight(< T as Config >::WeightInfo::set_mpc_address())] + pub fn set_mpc_address(origin: OriginFor, addr: MpcAddress) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"set_mpc_address".to_vec(), @@ -339,27 +342,27 @@ pub mod pallet { ), Error::::AccessDenied ); - // Cannot set MPC address as it's already set - ensure!(MpcAddr::::get().is_clear(), Error::::MpcAddrNotUpdatable); - - // Set MPC account address - MpcAddr::::set(addr); - - // unpause bridge - Self::unpause_all_domains(); - - Ok(()) - } - - /// Mark the give dest domainID with chainID to be enabled - #[pallet::call_index(3)] - #[pallet::weight(::WeightInfo::register_domain())] - pub fn register_domain( - origin: OriginFor, - dest_domain_id: DomainID, - dest_chain_id: ChainID, - ) -> DispatchResult { - ensure!( + // Cannot set MPC address as it's already set + ensure!(MpcAddr::::get().is_clear(), Error::::MpcAddrNotUpdatable); + + // Set MPC account address + MpcAddr::::set(addr); + + // unpause bridge + Self::unpause_all_domains(); + + Ok(()) + } + + /// Mark the give dest domainID with chainID to be enabled + #[pallet::call_index(3)] + #[pallet::weight(< T as Config >::WeightInfo::register_domain())] + pub fn register_domain( + origin: OriginFor, + dest_domain_id: DomainID, + dest_chain_id: ChainID, + ) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"register_domain".to_vec(), @@ -368,31 +371,31 @@ pub mod pallet { Error::::AccessDenied ); - DestDomainIds::::insert(dest_domain_id, true); - DestChainIds::::insert(dest_domain_id, dest_chain_id); - - // Emit register dest domain event - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::RegisterDestDomain { - sender, - domain_id: dest_domain_id, - chain_id: dest_chain_id, - }); - Ok(()) - } - - /// Mark the give dest domainID with chainID to be disabled - #[pallet::call_index(4)] - #[pallet::weight(::WeightInfo::unregister_domain())] - pub fn unregister_domain( - origin: OriginFor, - dest_domain_id: DomainID, - dest_chain_id: ChainID, - ) -> DispatchResult { - ensure!( + DestDomainIds::::insert(dest_domain_id, true); + DestChainIds::::insert(dest_domain_id, dest_chain_id); + + // Emit register dest domain event + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::RegisterDestDomain { + sender, + domain_id: dest_domain_id, + chain_id: dest_chain_id, + }); + Ok(()) + } + + /// Mark the give dest domainID with chainID to be disabled + #[pallet::call_index(4)] + #[pallet::weight(< T as Config >::WeightInfo::unregister_domain())] + pub fn unregister_domain( + origin: OriginFor, + dest_domain_id: DomainID, + dest_chain_id: ChainID, + ) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"unregister_domain".to_vec(), @@ -400,143 +403,143 @@ pub mod pallet { ), Error::::AccessDenied ); - ensure!( + ensure!( DestDomainIds::::get(dest_domain_id) && DestChainIds::::get(dest_domain_id).is_some(), Error::::DestDomainNotSupported ); - let co_chain_id = DestChainIds::::get(dest_domain_id).unwrap(); - ensure!(co_chain_id == dest_chain_id, Error::::DestChainIDNotMatch); - - DestDomainIds::::remove(dest_domain_id); - DestChainIds::::remove(dest_domain_id); - - // Emit unregister dest domain event - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::UnregisterDestDomain { - sender, - domain_id: dest_domain_id, - chain_id: dest_chain_id, - }); - Ok(()) - } - - /// Initiates a transfer. - #[transactional] - #[pallet::call_index(5)] - #[pallet::weight(::WeightInfo::deposit())] - pub fn deposit( - origin: OriginFor, - asset: Box, - dest: Box, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); - - // Extract dest (MultiLocation) to get corresponding dest domainID and Ethereum - // recipient address - let (recipient, dest_domain_id) = - T::ExtractDestData::extract_dest(&dest).ok_or(Error::::ExtractDestDataFailed)?; - - ensure!(!IsPaused::::get(dest_domain_id), Error::::BridgePaused); - - ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); - - // Extract asset (MultiAsset) to get corresponding ResourceId, transfer amount and the - // transfer type - let (resource_id, amount, transfer_type) = - Self::extract_asset(&asset.clone()).ok_or(Error::::AssetNotBound)?; - // Return error if no fee handler set - let fee = T::FeeHandler::get_fee(dest_domain_id, *asset.clone()) - .ok_or(Error::::MissingFeeConfig)?; - - ensure!(amount > fee, Error::::FeeTooExpensive); - - // Withdraw `amount` of asset from sender - T::AssetTransactor::withdraw_asset( - &asset, - &Junction::AccountId32 { network: None, id: sender.clone().into() }.into(), - None, - ) - .map_err(|_| Error::::TransactFailed)?; - - // Deposit `fee` of asset to treasury account - T::AssetTransactor::deposit_asset( - &(asset.id, Fungible(fee)).into(), - &Junction::AccountId32 { network: None, id: T::FeeReserveAccount::get().into() } - .into(), - // Put empty message hash here because we are not sending XCM message - &XcmContext::with_message_id([0; 32]), - ) - .map_err(|_| Error::::TransactFailed)?; - - let bridge_amount = amount - fee; - - let token_reserved_account = Self::get_token_reserved_account(&asset.id) - .ok_or(Error::::NoLiquidityHolderAccountBound)?; - - // Deposit `bridge_amount` of asset to reserve account if asset is reserved in local - // chain. - if T::IsReserve::contains(&asset, &MultiLocation::here()) { - T::AssetTransactor::deposit_asset( - &(asset.id, Fungible(bridge_amount)).into(), - &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), - // Put empty message hash here because we are not sending XCM message - &XcmContext::with_message_id([0; 32]), - ) - .map_err(|_| Error::::TransactFailed)?; - } - - // Bump deposit nonce - let deposit_nonce = DepositCounts::::get(dest_domain_id); - DepositCounts::::insert( - dest_domain_id, - deposit_nonce.checked_add(1).ok_or(Error::::DepositNonceOverflow)?, - ); - - // convert the asset decimal - let decimal_converted_amount = - T::DecimalConverter::convert_to(&(asset.id, bridge_amount).into()) - .ok_or(Error::::DecimalConversionFail)?; - - // Emit Deposit event - Self::deposit_event(Event::Deposit { - dest_domain_id, - resource_id, - deposit_nonce, - sender: sender.clone(), - transfer_type, - deposit_data: Self::create_deposit_data(decimal_converted_amount, recipient), - handler_response: vec![], - }); - - // Emit FeeCollected event - Self::deposit_event(Event::FeeCollected { - fee_payer: sender, - dest_domain_id, - resource_id, - fee_amount: fee, - fee_asset_id: asset.id, - }); - - Ok(()) - } - - /// This method is used to trigger the process for retrying failed deposits on the MPC side. - #[transactional] - #[pallet::call_index(6)] - #[pallet::weight(::WeightInfo::retry())] - pub fn retry( - origin: OriginFor, - deposit_on_block_height: u128, - dest_domain_id: DomainID, - ) -> DispatchResult { - ensure!( + let co_chain_id = DestChainIds::::get(dest_domain_id).unwrap(); + ensure!(co_chain_id == dest_chain_id, Error::::DestChainIDNotMatch); + + DestDomainIds::::remove(dest_domain_id); + DestChainIds::::remove(dest_domain_id); + + // Emit unregister dest domain event + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::UnregisterDestDomain { + sender, + domain_id: dest_domain_id, + chain_id: dest_chain_id, + }); + Ok(()) + } + + /// Initiates a transfer. + #[transactional] + #[pallet::call_index(5)] + #[pallet::weight(< T as Config >::WeightInfo::deposit())] + pub fn deposit( + origin: OriginFor, + asset: Box, + dest: Box, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); + + // Extract dest (MultiLocation) to get corresponding dest domainID and Ethereum + // recipient address + let (recipient, dest_domain_id) = + T::ExtractDestData::extract_dest(&dest).ok_or(Error::::ExtractDestDataFailed)?; + + ensure!(!IsPaused::::get(dest_domain_id), Error::::BridgePaused); + + ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); + + // Extract asset (MultiAsset) to get corresponding ResourceId, transfer amount and the + // transfer type + let (resource_id, amount, transfer_type) = + Self::extract_asset(&asset.clone()).ok_or(Error::::AssetNotBound)?; + // Return error if no fee handler set + let fee = T::FeeHandler::get_fee(dest_domain_id, *asset.clone()) + .ok_or(Error::::MissingFeeConfig)?; + + ensure!(amount > fee, Error::::FeeTooExpensive); + + // Withdraw `amount` of asset from sender + T::AssetTransactor::withdraw_asset( + &asset, + &Junction::AccountId32 { network: None, id: sender.clone().into() }.into(), + None, + ) + .map_err(|_| Error::::TransactFailed)?; + + // Deposit `fee` of asset to treasury account + T::AssetTransactor::deposit_asset( + &(asset.id, Fungible(fee)).into(), + &Junction::AccountId32 { network: None, id: T::FeeReserveAccount::get().into() } + .into(), + // Put empty message hash here because we are not sending XCM message + &XcmContext::with_message_id([0; 32]), + ) + .map_err(|_| Error::::TransactFailed)?; + + let bridge_amount = amount - fee; + + let token_reserved_account = Self::get_token_reserved_account(&asset.id) + .ok_or(Error::::NoLiquidityHolderAccountBound)?; + + // Deposit `bridge_amount` of asset to reserve account if asset is reserved in local + // chain. + if T::IsReserve::contains(&asset, &MultiLocation::here()) { + T::AssetTransactor::deposit_asset( + &(asset.id, Fungible(bridge_amount)).into(), + &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), + // Put empty message hash here because we are not sending XCM message + &XcmContext::with_message_id([0; 32]), + ) + .map_err(|_| Error::::TransactFailed)?; + } + + // Bump deposit nonce + let deposit_nonce = DepositCounts::::get(dest_domain_id); + DepositCounts::::insert( + dest_domain_id, + deposit_nonce.checked_add(1).ok_or(Error::::DepositNonceOverflow)?, + ); + + // convert the asset decimal + let decimal_converted_amount = + T::DecimalConverter::convert_to(&(asset.id, bridge_amount).into()) + .ok_or(Error::::DecimalConversionFail)?; + + // Emit Deposit event + Self::deposit_event(Event::Deposit { + dest_domain_id, + resource_id, + deposit_nonce, + sender: sender.clone(), + transfer_type, + deposit_data: Self::create_deposit_data(decimal_converted_amount, recipient), + handler_response: vec![], + }); + + // Emit FeeCollected event + Self::deposit_event(Event::FeeCollected { + fee_payer: sender, + dest_domain_id, + resource_id, + fee_amount: fee, + fee_asset_id: asset.id, + }); + + Ok(()) + } + + /// This method is used to trigger the process for retrying failed deposits on the MPC side. + #[transactional] + #[pallet::call_index(6)] + #[pallet::weight(< T as Config >::WeightInfo::retry())] + pub fn retry( + origin: OriginFor, + deposit_on_block_height: u128, + dest_domain_id: DomainID, + ) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"retry".to_vec(), @@ -544,91 +547,91 @@ pub mod pallet { ), Error::::AccessDenied ); - ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); - ensure!(!IsPaused::::get(dest_domain_id), Error::::BridgePaused); - ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); - - // Emit retry event - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::::Retry { - deposit_on_block_height, - dest_domain_id, - sender, - }); - Ok(()) - } - - /// Executes a batch of deposit proposals (only if signature is signed by MPC). - #[transactional] - #[pallet::call_index(7)] - #[pallet::weight(::WeightInfo::execute_proposal(proposals.len() as u32))] - pub fn execute_proposal( - _origin: OriginFor, - proposals: Vec, - signature: Vec, - ) -> DispatchResult { - // Check MPC address and bridge status - ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); - - ensure!(!proposals.is_empty(), Error::::EmptyProposalList); - - // parse proposals and construct signing message to meet EIP712 typed data - let final_message = Self::construct_ecdsa_signing_proposals_data(&proposals); - - // Verify MPC signature - ensure!( + ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); + ensure!(!IsPaused::::get(dest_domain_id), Error::::BridgePaused); + ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); + + // Emit retry event + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::::Retry { + deposit_on_block_height, + dest_domain_id, + sender, + }); + Ok(()) + } + + /// Executes a batch of deposit proposals (only if signature is signed by MPC). + #[transactional] + #[pallet::call_index(7)] + #[pallet::weight(< T as Config >::WeightInfo::execute_proposal(proposals.len() as u32))] + pub fn execute_proposal( + _origin: OriginFor, + proposals: Vec, + signature: Vec, + ) -> DispatchResult { + // Check MPC address and bridge status + ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); + + ensure!(!proposals.is_empty(), Error::::EmptyProposalList); + + // parse proposals and construct signing message to meet EIP712 typed data + let final_message = Self::construct_ecdsa_signing_proposals_data(&proposals); + + // Verify MPC signature + ensure!( Self::verify_by_mpc_address(final_message, signature), Error::::BadMpcSignature ); - // Execute proposals one by one. - // Note if one proposal failed to execute, we emit `FailedHandlerExecution` rather - // than revert whole transaction - for proposal in proposals.iter() { - Self::execute_proposal_internal(proposal).map_or_else( - |e| { - let err_msg: &'static str = e.into(); - // Any error during proposal list execution will emit FailedHandlerExecution - Self::deposit_event(Event::FailedHandlerExecution { - error: err_msg.as_bytes().to_vec(), - origin_domain_id: proposal.origin_domain_id, - deposit_nonce: proposal.deposit_nonce, - }); - }, - |_| { - // Update proposal status - Self::set_proposal_executed( - proposal.deposit_nonce, - proposal.origin_domain_id, - ); - - // Emit ProposalExecution - Self::deposit_event(Event::ProposalExecution { - origin_domain_id: proposal.origin_domain_id, - deposit_nonce: proposal.deposit_nonce, - data_hash: keccak_256( - &[ - proposal.data.clone(), - T::PalletId::get().into_account_truncating(), - ] - .concat(), - ), - }); - }, - ); - } - - Ok(()) - } - - /// Pause all registered bridges - #[pallet::call_index(8)] - #[pallet::weight(::WeightInfo::pause_all_bridges())] - pub fn pause_all_bridges(origin: OriginFor) -> DispatchResult { - ensure!( + // Execute proposals one by one. + // Note if one proposal failed to execute, we emit `FailedHandlerExecution` rather + // than revert whole transaction + for proposal in proposals.iter() { + Self::execute_proposal_internal(proposal).map_or_else( + |e| { + let err_msg: &'static str = e.into(); + // Any error during proposal list execution will emit FailedHandlerExecution + Self::deposit_event(Event::FailedHandlerExecution { + error: err_msg.as_bytes().to_vec(), + origin_domain_id: proposal.origin_domain_id, + deposit_nonce: proposal.deposit_nonce, + }); + }, + |_| { + // Update proposal status + Self::set_proposal_executed( + proposal.deposit_nonce, + proposal.origin_domain_id, + ); + + // Emit ProposalExecution + Self::deposit_event(Event::ProposalExecution { + origin_domain_id: proposal.origin_domain_id, + deposit_nonce: proposal.deposit_nonce, + data_hash: keccak_256( + &[ + proposal.data.clone(), + T::PalletId::get().into_account_truncating(), + ] + .concat(), + ), + }); + }, + ); + } + + Ok(()) + } + + /// Pause all registered bridges + #[pallet::call_index(8)] + #[pallet::weight(< T as Config >::WeightInfo::pause_all_bridges())] + pub fn pause_all_bridges(origin: OriginFor) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"pause_all_bridges".to_vec(), @@ -637,24 +640,24 @@ pub mod pallet { Error::::AccessDenied ); - // Pause all bridges - Self::pause_all_domains(); + // Pause all bridges + Self::pause_all_domains(); - // Emit AllBridgePaused - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::AllBridgePaused { sender }); + // Emit AllBridgePaused + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::AllBridgePaused { sender }); - Ok(()) - } + Ok(()) + } - /// Unpause all registered bridges - #[pallet::call_index(9)] - #[pallet::weight(::WeightInfo::unpause_all_bridges())] - pub fn unpause_all_bridges(origin: OriginFor) -> DispatchResult { - ensure!( + /// Unpause all registered bridges + #[pallet::call_index(9)] + #[pallet::weight(< T as Config >::WeightInfo::unpause_all_bridges())] + pub fn unpause_all_bridges(origin: OriginFor) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"unpause_all_bridges".to_vec(), @@ -663,638 +666,640 @@ pub mod pallet { Error::::AccessDenied ); - // Make sure MPC address is setup - ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); - - // Unpause all bridges - Self::unpause_all_domains(); - - // Emit AllBridgeUnpaused - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::AllBridgeUnpaused { sender }); - - Ok(()) - } - } - - impl AssetTypeIdentifier for Pallet { - fn is_native_asset(asset: &MultiAsset) -> bool { - let native_locations = [ - MultiLocation::here(), - MultiLocation::new(1, X1(Parachain(T::get().into()))), - ]; - - match (&asset.id, &asset.fun) { - (Concrete(ref id), Fungible(_)) => { - native_locations.contains(id) - }, - _ => false, - } - } - } - - - impl Bridge for Pallet where - ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, - { - fn transfer(sender: [u8; 32], - asset: MultiAsset, - dest: MultiLocation) -> DispatchResult { - let sender_origin = OriginFor::::from(RawOrigin::Signed(sender.into())); - Pallet::::deposit(sender_origin, Box::from(asset), Box::from(dest))?; - - Ok(()) - } - } - - impl Pallet - where - ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, - { - /// Verifies that EIP712 typed proposal data is signed by MPC address - #[allow(dead_code)] - fn verify_by_mpc_address(signing_message: [u8; 32], signature: Vec) -> bool { - let sig = match signature.try_into() { - Ok(_sig) => _sig, - Err(error) => return false, - }; - - // recover the signing address - if let Ok(pubkey) = - // recover the uncompressed pubkey - secp256k1_ecdsa_recover(&sig, &signing_message) - { - let address = Self::public_key_to_address(&pubkey); - - address == MpcAddr::::get().0 - } else { - false - } - } - - /// Return the TokenReservedAccount address by the given token - pub fn get_token_reserved_account(token_id: &AssetId) -> Option<[u8; 32]> { - T::TransferReserveAccounts::get() - .get(token_id) - .map(|account| (*account).clone().into()) - } - - /// convert the ECDSA 64-byte uncompressed pubkey to H160 address - pub fn public_key_to_address(public_key: &[u8]) -> [u8; 20] { - let hash = keccak_256(public_key); - let final_hash = array_ref![&hash, 12, 20]; - *final_hash - } - - /// Parse proposals and construct the original signing message - pub fn construct_ecdsa_signing_proposals_data(proposals: &Vec) -> [u8; 32] { - let proposals_typehash = keccak_256( - "Proposals(Proposal[] proposals)Proposal(uint8 originDomainID,uint64 depositNonce,bytes32 resourceID,bytes data)" - .as_bytes(), - ); - let proposal_typehash = keccak_256( - "Proposal(uint8 originDomainID,uint64 depositNonce,bytes32 resourceID,bytes data)" - .as_bytes(), - ); - - if proposals.is_empty() { - return [0u8; 32]; - } - - let mut keccak_data = Vec::new(); - for prop in proposals { - let proposal_domain_id_token = Token::Uint(prop.origin_domain_id.into()); - let proposal_deposit_nonce_token = Token::Uint(prop.deposit_nonce.into()); - let proposal_resource_id_token = Token::FixedBytes(prop.resource_id.to_vec()); - let proposal_data_token = Token::FixedBytes(keccak_256(&prop.data).to_vec()); - - keccak_data.push(keccak_256(&abi_encode(&[ - Token::FixedBytes(proposal_typehash.to_vec()), - proposal_domain_id_token, - proposal_deposit_nonce_token, - proposal_resource_id_token, - proposal_data_token, - ]))); - } - - // flatten the keccak_data into vec - let mut final_keccak_data = Vec::new(); - for data in keccak_data { - for d in data { - final_keccak_data.push(d) - } - } - - let final_keccak_data_input = &vec![SolidityDataType::Bytes(&final_keccak_data)]; - let bytes = encode_packed(final_keccak_data_input); - let hashed_keccak_data = keccak_256(bytes.as_slice()); - - let struct_hash = keccak_256(&abi_encode(&[ - Token::FixedBytes(proposals_typehash.to_vec()), - Token::FixedBytes(hashed_keccak_data.to_vec()), - ])); - - // domain separator - let default_eip712_domain = eip712::EIP712Domain::default(); - let eip712_domain = eip712::EIP712Domain { - name: b"Bridge".to_vec(), - version: b"3.1.0".to_vec(), - chain_id: T::EIP712ChainID::get(), - verifying_contract: T::DestVerifyingContractAddress::get(), - salt: default_eip712_domain.salt, - }; - let domain_separator = eip712_domain.separator(); - - let typed_data_hash_input = &vec![ - SolidityDataType::String("\x19\x01"), - SolidityDataType::Bytes(&domain_separator), - SolidityDataType::Bytes(&struct_hash), - ]; - let bytes = encode_packed(typed_data_hash_input); - keccak_256(bytes.as_slice()) - } - - /// Extract asset id and transfer amount from `MultiAsset`, currently only fungible asset - /// are supported. - fn extract_asset(asset: &MultiAsset) -> Option<(ResourceId, u128, TransferType)> { - match (&asset.fun, &asset.id) { - (Fungible(amount), _) => { - T::ResourcePairs::get().iter().position(|a| a.0 == asset.id).map(|idx| { - (T::ResourcePairs::get()[idx].1, *amount, TransferType::FungibleTransfer) - }) - }, - _ => None, - } - } - - pub fn create_deposit_data(amount: u128, recipient: Vec) -> Vec { - [ - &Self::hex_zero_padding_32(amount), - &Self::hex_zero_padding_32(recipient.len() as u128), - recipient.as_slice(), - ] - .concat() - .to_vec() - } - - /// Extract transfer amount and recipient location from deposit data. - /// For fungible transfer, data passed into the function should be constructed as follows: - /// amount uint256 bytes 0 - 32 - /// recipient data length uint256 bytes 32 - 64 - /// recipient data bytes bytes 64 - END - /// - /// Only fungible transfer is supported so far. - fn extract_deposit_data(data: &Vec) -> Result<(u128, MultiLocation), DispatchError> { - if data.len() < 64 { - return Err(Error::::InvalidDepositData.into()); - } - - let amount: u128 = U256::from_big_endian(&data[0..32]) - .try_into() - .map_err(|_| Error::::InvalidDepositData)?; - let recipient_len: usize = U256::from_big_endian(&data[32..64]) - .try_into() - .map_err(|_| Error::::InvalidDepositData)?; - if (data.len() - 64) != recipient_len { - return Err(Error::::InvalidDepositData.into()); - } - - let recipient = data[64..data.len()].to_vec(); - if let Ok(location) = ::decode(&mut recipient.as_slice()) { - Ok((amount, location)) - } else { - Err(Error::::InvalidDepositData.into()) - } - } - - fn rid_to_assetid(rid: &ResourceId) -> Option { - T::ResourcePairs::get() - .iter() - .position(|a| &a.1 == rid) - .map(|idx| T::ResourcePairs::get()[idx].0) - } - - fn hex_zero_padding_32(i: u128) -> [u8; 32] { - let mut result = [0u8; 32]; - U256::from(i).to_big_endian(&mut result); - result - } - - /// Return true if deposit nonce has been used - pub fn is_proposal_executed(nonce: DepositNonce, domain_id: DomainID) -> bool { - (UsedNonces::::get(domain_id, nonce / 64) & (1 << (nonce % 64))) != 0 - } - - /// Set bit mask for specific nonce as used - fn set_proposal_executed(nonce: DepositNonce, domain_id: DomainID) { - let mut current_nonces = UsedNonces::::get(domain_id, nonce / 64); - current_nonces |= 1 << (nonce % 64); - UsedNonces::::insert(domain_id, nonce / 64, current_nonces); - } - - /// Execute a single proposal - fn execute_proposal_internal(proposal: &Proposal) -> DispatchResult { - // Check if dest domain bridge is paused - ensure!(!IsPaused::::get(proposal.origin_domain_id), Error::::BridgePaused); - // Check if domain is supported - ensure!( + // Make sure MPC address is setup + ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); + + // Unpause all bridges + Self::unpause_all_domains(); + + // Emit AllBridgeUnpaused + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::AllBridgeUnpaused { sender }); + + Ok(()) + } + } + + impl> AssetTypeIdentifier for Pallet { + fn is_native_asset(asset: &MultiAsset) -> bool { + let native_locations = [ + MultiLocation::here(), + MultiLocation::new(1, X1(Parachain(T::get().into()))), + ]; + + match (&asset.id, &asset.fun) { + (Concrete(ref id), Fungible(_)) => { + native_locations.contains(id) + } + _ => false, + } + } + } + + + impl Bridge for Pallet where + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, + { + fn transfer(sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation) -> DispatchResult { + let sender_origin = OriginFor::::from(RawOrigin::Signed(sender.into())); + Pallet::::deposit(sender_origin, Box::from(asset), Box::from(dest))?; + + Ok(()) + } + } + + impl Pallet + where + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, + { + /// Verifies that EIP712 typed proposal data is signed by MPC address + #[allow(dead_code)] + fn verify_by_mpc_address(signing_message: [u8; 32], signature: Vec) -> bool { + let sig = match signature.try_into() { + Ok(_sig) => _sig, + Err(error) => return false, + }; + + // recover the signing address + if let Ok(pubkey) = + // recover the uncompressed pubkey + secp256k1_ecdsa_recover(&sig, &signing_message) + { + let address = Self::public_key_to_address(&pubkey); + + address == MpcAddr::::get().0 + } else { + false + } + } + + /// Return the TokenReservedAccount address by the given token + pub fn get_token_reserved_account(token_id: &AssetId) -> Option<[u8; 32]> { + T::TransferReserveAccounts::get() + .get(token_id) + .map(|account| (*account).clone().into()) + } + + /// convert the ECDSA 64-byte uncompressed pubkey to H160 address + pub fn public_key_to_address(public_key: &[u8]) -> [u8; 20] { + let hash = keccak_256(public_key); + let final_hash = array_ref![&hash, 12, 20]; + *final_hash + } + + /// Parse proposals and construct the original signing message + pub fn construct_ecdsa_signing_proposals_data(proposals: &Vec) -> [u8; 32] { + let proposals_typehash = keccak_256( + "Proposals(Proposal[] proposals)Proposal(uint8 originDomainID,uint64 depositNonce,bytes32 resourceID,bytes data)" + .as_bytes(), + ); + let proposal_typehash = keccak_256( + "Proposal(uint8 originDomainID,uint64 depositNonce,bytes32 resourceID,bytes data)" + .as_bytes(), + ); + + if proposals.is_empty() { + return [0u8; 32]; + } + + let mut keccak_data = Vec::new(); + for prop in proposals { + let proposal_domain_id_token = Token::Uint(prop.origin_domain_id.into()); + let proposal_deposit_nonce_token = Token::Uint(prop.deposit_nonce.into()); + let proposal_resource_id_token = Token::FixedBytes(prop.resource_id.to_vec()); + let proposal_data_token = Token::FixedBytes(keccak_256(&prop.data).to_vec()); + + keccak_data.push(keccak_256(&abi_encode(&[ + Token::FixedBytes(proposal_typehash.to_vec()), + proposal_domain_id_token, + proposal_deposit_nonce_token, + proposal_resource_id_token, + proposal_data_token, + ]))); + } + + // flatten the keccak_data into vec + let mut final_keccak_data = Vec::new(); + for data in keccak_data { + for d in data { + final_keccak_data.push(d) + } + } + + let final_keccak_data_input = &vec![SolidityDataType::Bytes(&final_keccak_data)]; + let bytes = encode_packed(final_keccak_data_input); + let hashed_keccak_data = keccak_256(bytes.as_slice()); + + let struct_hash = keccak_256(&abi_encode(&[ + Token::FixedBytes(proposals_typehash.to_vec()), + Token::FixedBytes(hashed_keccak_data.to_vec()), + ])); + + // domain separator + let default_eip712_domain = eip712::EIP712Domain::default(); + let eip712_domain = eip712::EIP712Domain { + name: b"Bridge".to_vec(), + version: b"3.1.0".to_vec(), + chain_id: T::EIP712ChainID::get(), + verifying_contract: T::DestVerifyingContractAddress::get(), + salt: default_eip712_domain.salt, + }; + let domain_separator = eip712_domain.separator(); + + let typed_data_hash_input = &vec![ + SolidityDataType::String("\x19\x01"), + SolidityDataType::Bytes(&domain_separator), + SolidityDataType::Bytes(&struct_hash), + ]; + let bytes = encode_packed(typed_data_hash_input); + keccak_256(bytes.as_slice()) + } + + /// Extract asset id and transfer amount from `MultiAsset`, currently only fungible asset + /// are supported. + fn extract_asset(asset: &MultiAsset) -> Option<(ResourceId, u128, TransferType)> { + match (&asset.fun, &asset.id) { + (Fungible(amount), _) => { + T::ResourcePairs::get().iter().position(|a| a.0 == asset.id).map(|idx| { + (T::ResourcePairs::get()[idx].1, *amount, TransferType::FungibleTransfer) + }) + } + _ => None, + } + } + + pub fn create_deposit_data(amount: u128, recipient: Vec) -> Vec { + [ + &Self::hex_zero_padding_32(amount), + &Self::hex_zero_padding_32(recipient.len() as u128), + recipient.as_slice(), + ] + .concat() + .to_vec() + } + + /// Extract transfer amount and recipient location from deposit data. + /// For fungible transfer, data passed into the function should be constructed as follows: + /// amount uint256 bytes 0 - 32 + /// recipient data length uint256 bytes 32 - 64 + /// recipient data bytes bytes 64 - END + /// + /// Only fungible transfer is supported so far. + fn extract_deposit_data(data: &Vec) -> Result<(u128, MultiLocation), DispatchError> { + if data.len() < 64 { + return Err(Error::::InvalidDepositData.into()); + } + + let amount: u128 = U256::from_big_endian(&data[0..32]) + .try_into() + .map_err(|_| Error::::InvalidDepositData)?; + let recipient_len: usize = U256::from_big_endian(&data[32..64]) + .try_into() + .map_err(|_| Error::::InvalidDepositData)?; + if (data.len() - 64) != recipient_len { + return Err(Error::::InvalidDepositData.into()); + } + + let recipient = data[64..data.len()].to_vec(); + if let Ok(location) = ::decode(&mut recipient.as_slice()) { + Ok((amount, location)) + } else { + Err(Error::::InvalidDepositData.into()) + } + } + + fn rid_to_assetid(rid: &ResourceId) -> Option { + T::ResourcePairs::get() + .iter() + .position(|a| &a.1 == rid) + .map(|idx| T::ResourcePairs::get()[idx].0) + } + + fn hex_zero_padding_32(i: u128) -> [u8; 32] { + let mut result = [0u8; 32]; + U256::from(i).to_big_endian(&mut result); + result + } + + /// Return true if deposit nonce has been used + pub fn is_proposal_executed(nonce: DepositNonce, domain_id: DomainID) -> bool { + (UsedNonces::::get(domain_id, nonce / 64) & (1 << (nonce % 64))) != 0 + } + + /// Set bit mask for specific nonce as used + fn set_proposal_executed(nonce: DepositNonce, domain_id: DomainID) { + let mut current_nonces = UsedNonces::::get(domain_id, nonce / 64); + current_nonces |= 1 << (nonce % 64); + UsedNonces::::insert(domain_id, nonce / 64, current_nonces); + } + + /// Execute a single proposal + fn execute_proposal_internal(proposal: &Proposal) -> DispatchResult { + // Check if dest domain bridge is paused + ensure!(!IsPaused::::get(proposal.origin_domain_id), Error::::BridgePaused); + // Check if domain is supported + ensure!( DestDomainIds::::get(proposal.origin_domain_id), Error::::DestDomainNotSupported ); - // Check if proposal has executed - ensure!( + // Check if proposal has executed + ensure!( !Self::is_proposal_executed(proposal.deposit_nonce, proposal.origin_domain_id), Error::::ProposalAlreadyComplete ); - // Extract ResourceId from proposal data to get corresponding asset (MultiAsset) - let asset_id = - Self::rid_to_assetid(&proposal.resource_id).ok_or(Error::::AssetNotBound)?; - // Extract Receipt from proposal data to get corresponding location (MultiLocation) - let (amount, location) = Self::extract_deposit_data(&proposal.data)?; - - // convert the asset decimal - let decimal_converted_asset = - T::DecimalConverter::convert_from(&(asset_id, amount).into()) - .ok_or(Error::::DecimalConversionFail)?; - - let token_reserved_account = Self::get_token_reserved_account(&asset_id) - .ok_or(Error::::NoLiquidityHolderAccountBound)?; - - // Withdraw `decimal_converted_asset` of asset from reserve account - if T::IsReserve::contains(&decimal_converted_asset, &MultiLocation::here()) { - T::AssetTransactor::withdraw_asset( - &decimal_converted_asset, - &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), - None, - ) - .map_err(|_| Error::::TransactFailed)?; - } - - // Deposit `decimal_converted_asset` of asset to dest location - T::AssetTransactor::deposit_asset( - &decimal_converted_asset, - &location, - // Put empty message hash here because we are not sending XCM message - &XcmContext::with_message_id([0; 32]), - ) - .map_err(|_| Error::::TransactFailed)?; - - Ok(()) - } - - /// unpause all registered domains in the storage - fn unpause_all_domains() { - DestDomainIds::::iter_keys().for_each(|d| IsPaused::::insert(d, false)); - IsPaused::::iter_keys().for_each(|d| IsPaused::::insert(d, false)); - } - - /// pause all registered domains in the storage - fn pause_all_domains() { - DestDomainIds::::iter_keys().for_each(|d| IsPaused::::insert(d, true)); - IsPaused::::iter_keys().for_each(|d| IsPaused::::insert(d, true)); - } - } - - #[cfg(test)] - mod test { - use crate as bridge; - use crate::{ - mock::{AstrAssetId, AstrLocation, AstrResourceId}, - DestChainIds, DestDomainIds, Error, Event as SygmaBridgeEvent, IsPaused, MpcAddr, - Proposal, - }; - use bridge::mock::{ - assert_events, new_test_ext, slice_to_generalkey, AccessSegregator, Assets, Balances, - BridgeAccountNative, BridgeAccountOtherTokens, BridgePalletIndex, NativeLocation, - NativeResourceId, Runtime, RuntimeEvent, RuntimeOrigin as Origin, SygmaBasicFeeHandler, - SygmaBridge, SygmaFeeHandlerRouter, SygmaPercentageFeeHandler, TreasuryAccount, - UsdtAssetId, UsdtLocation, UsdtResourceId, ALICE, ASSET_OWNER, BOB, DEST_DOMAIN_ID, - ENDOWED_BALANCE, - }; - use codec::{self, Encode}; - use frame_support::{ - assert_noop, assert_ok, crypto::ecdsa::ECDSAExt, - traits::tokens::fungibles::Create as FungibleCerate, - }; - use parachains_common::AccountId; - use primitive_types::U256; - use sp_core::{ecdsa, ByteArray, Pair}; - use sp_std::{boxed::Box, vec}; - use sygma_fee_handler_router::FeeHandlerType; - use sygma_traits::{DomainID, MpcAddress, TransferType}; - use xcm::latest::prelude::*; - - #[test] - fn get_token_reserved_account_test() { - new_test_ext().execute_with(|| { - assert_eq!( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()).unwrap(), - BridgeAccountOtherTokens::get().as_slice() - ); - assert_eq!( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()).unwrap(), - BridgeAccountNative::get().as_slice() - ); - assert_eq!( - SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()).unwrap(), - BridgeAccountOtherTokens::get().as_slice() - ); - - // unknown token should return None - assert_eq!( - SygmaBridge::get_token_reserved_account( - &MultiLocation::new( - 2, - X3( - Parachain(1000), - slice_to_generalkey(b"sygma"), - slice_to_generalkey(b"unknown"), - ), - ) - .into() - ), - None - ); - }) - } - - #[test] - fn set_mpc_address() { - new_test_ext().execute_with(|| { - let default_addr: MpcAddress = MpcAddress::default(); - let test_mpc_addr_a: MpcAddress = MpcAddress([1u8; 20]); - let test_mpc_addr_b: MpcAddress = MpcAddress([2u8; 20]); - - assert_eq!(MpcAddr::::get(), default_addr); - - // set to test_mpc_addr_a - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr_a)); - assert_eq!(MpcAddr::::get(), test_mpc_addr_a); - - // set to test_mpc_addr_b: should be MpcAddrNotUpdatable error - assert_noop!( + // Extract ResourceId from proposal data to get corresponding asset (MultiAsset) + let asset_id = + Self::rid_to_assetid(&proposal.resource_id).ok_or(Error::::AssetNotBound)?; + // Extract Receipt from proposal data to get corresponding location (MultiLocation) + let (amount, location) = Self::extract_deposit_data(&proposal.data)?; + + // convert the asset decimal + let decimal_converted_asset = + T::DecimalConverter::convert_from(&(asset_id, amount).into()) + .ok_or(Error::::DecimalConversionFail)?; + + let token_reserved_account = Self::get_token_reserved_account(&asset_id) + .ok_or(Error::::NoLiquidityHolderAccountBound)?; + + // Withdraw `decimal_converted_asset` of asset from reserve account + if T::IsReserve::contains(&decimal_converted_asset, &MultiLocation::here()) { + T::AssetTransactor::withdraw_asset( + &decimal_converted_asset, + &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), + None, + ) + .map_err(|_| Error::::TransactFailed)?; + } + + // Deposit `decimal_converted_asset` of asset to dest location + T::AssetTransactor::deposit_asset( + &decimal_converted_asset, + &location, + // Put empty message hash here because we are not sending XCM message + &XcmContext::with_message_id([0; 32]), + ) + .map_err(|_| Error::::TransactFailed)?; + + Ok(()) + } + + /// unpause all registered domains in the storage + fn unpause_all_domains() { + DestDomainIds::::iter_keys().for_each(|d| IsPaused::::insert(d, false)); + IsPaused::::iter_keys().for_each(|d| IsPaused::::insert(d, false)); + } + + /// pause all registered domains in the storage + fn pause_all_domains() { + DestDomainIds::::iter_keys().for_each(|d| IsPaused::::insert(d, true)); + IsPaused::::iter_keys().for_each(|d| IsPaused::::insert(d, true)); + } + } + + #[cfg(test)] + mod test { + use codec::{self, Encode}; + use frame_support::{ + assert_noop, assert_ok, crypto::ecdsa::ECDSAExt, + traits::tokens::fungibles::Create as FungibleCerate, + }; + use parachains_common::AccountId; + use primitive_types::U256; + use sp_core::{ByteArray, ecdsa, Pair}; + use sp_std::{boxed::Box, vec}; + use xcm::latest::prelude::*; + + use bridge::mock::{ + AccessSegregator, ALICE, assert_events, ASSET_OWNER, Assets, Balances, + BOB, BridgeAccountNative, BridgeAccountOtherTokens, BridgePalletIndex, + DEST_DOMAIN_ID, ENDOWED_BALANCE, NativeLocation, NativeResourceId, new_test_ext, + Runtime, RuntimeEvent, RuntimeOrigin as Origin, slice_to_generalkey, + SygmaBasicFeeHandler, SygmaBridge, SygmaFeeHandlerRouter, SygmaPercentageFeeHandler, TreasuryAccount, UsdtAssetId, UsdtLocation, + UsdtResourceId, + }; + use sygma_fee_handler_router::FeeHandlerType; + use sygma_traits::{DomainID, MpcAddress, TransferType}; + + use crate as bridge; + use crate::{ + DestChainIds, + DestDomainIds, Error, Event as SygmaBridgeEvent, IsPaused, mock::{AstrAssetId, AstrLocation, AstrResourceId}, MpcAddr, + Proposal, + }; + + #[test] + fn get_token_reserved_account_test() { + new_test_ext().execute_with(|| { + assert_eq!( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()).unwrap(), + BridgeAccountOtherTokens::get().as_slice() + ); + assert_eq!( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()).unwrap(), + BridgeAccountNative::get().as_slice() + ); + assert_eq!( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()).unwrap(), + BridgeAccountOtherTokens::get().as_slice() + ); + + // unknown token should return None + assert_eq!( + SygmaBridge::get_token_reserved_account( + &MultiLocation::new( + 2, + X3( + Parachain(1000), + slice_to_generalkey(b"sygma"), + slice_to_generalkey(b"unknown"), + ), + ) + .into() + ), + None + ); + }) + } + + #[test] + fn set_mpc_address() { + new_test_ext().execute_with(|| { + let default_addr: MpcAddress = MpcAddress::default(); + let test_mpc_addr_a: MpcAddress = MpcAddress([1u8; 20]); + let test_mpc_addr_b: MpcAddress = MpcAddress([2u8; 20]); + + assert_eq!(MpcAddr::::get(), default_addr); + + // set to test_mpc_addr_a + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr_a)); + assert_eq!(MpcAddr::::get(), test_mpc_addr_a); + + // set to test_mpc_addr_b: should be MpcAddrNotUpdatable error + assert_noop!( SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr_b), bridge::Error::::MpcAddrNotUpdatable ); - // permission test: unauthorized account should not be able to set mpc address - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // permission test: unauthorized account should not be able to set mpc address + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::set_mpc_address(unauthorized_account, test_mpc_addr_a), bridge::Error::::AccessDenied ); - assert_eq!(MpcAddr::::get(), test_mpc_addr_a); - }) - } + assert_eq!(MpcAddr::::get(), test_mpc_addr_a); + }) + } - #[test] - fn pause_bridge() { - new_test_ext().execute_with(|| { - let default_addr = MpcAddress::default(); - assert_eq!(MpcAddr::::get(), default_addr); + #[test] + fn pause_bridge() { + new_test_ext().execute_with(|| { + let default_addr = MpcAddress::default(); + assert_eq!(MpcAddr::::get(), default_addr); - // register domain - assert_ok!(SygmaBridge::register_domain( + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // pause bridge, should be ok - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(IsPaused::::get(DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { - dest_domain_id: DEST_DOMAIN_ID, - })]); + // pause bridge, should be ok + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(IsPaused::::get(DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { + dest_domain_id: DEST_DOMAIN_ID, + })]); - // pause bridge again after paused, should be ok - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(IsPaused::::get(DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { - dest_domain_id: DEST_DOMAIN_ID, - })]); + // pause bridge again after paused, should be ok + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(IsPaused::::get(DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { + dest_domain_id: DEST_DOMAIN_ID, + })]); - // permission test: unauthorized account should not be able to pause bridge - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // permission test: unauthorized account should not be able to pause bridge + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::pause_bridge(unauthorized_account, DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - assert!(IsPaused::::get(DEST_DOMAIN_ID)); - }) - } + assert!(IsPaused::::get(DEST_DOMAIN_ID)); + }) + } - #[test] - fn unpause_bridge() { - new_test_ext().execute_with(|| { - let default_addr: MpcAddress = MpcAddress::default(); - assert_eq!(MpcAddr::::get(), default_addr); + #[test] + fn unpause_bridge() { + new_test_ext().execute_with(|| { + let default_addr: MpcAddress = MpcAddress::default(); + assert_eq!(MpcAddr::::get(), default_addr); - // register domain - assert_ok!(SygmaBridge::register_domain( + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { - dest_domain_id: DEST_DOMAIN_ID, - })]); + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { + dest_domain_id: DEST_DOMAIN_ID, + })]); - // bridge should be paused here - assert!(IsPaused::::get(DEST_DOMAIN_ID)); + // bridge should be paused here + assert!(IsPaused::::get(DEST_DOMAIN_ID)); - // ready to unpause bridge, should be ok - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgeUnpaused { - dest_domain_id: DEST_DOMAIN_ID, - })]); + // ready to unpause bridge, should be ok + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgeUnpaused { + dest_domain_id: DEST_DOMAIN_ID, + })]); - // try to unpause it again, should be error - assert_noop!( + // try to unpause it again, should be error + assert_noop!( SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID), bridge::Error::::BridgeUnpaused ); - // permission test: unauthorized account should not be able to unpause a recognized - // bridge - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // permission test: unauthorized account should not be able to unpause a recognized + // bridge + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::unpause_bridge(unauthorized_account, DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - assert!(!IsPaused::::get(DEST_DOMAIN_ID)); - }) - } - - #[test] - fn verify_mpc_signature_invalid_signature() { - new_test_ext().execute_with(|| { - let signature = vec![1u8]; - - // dummy proposals - let p1 = Proposal { - origin_domain_id: 1, - deposit_nonce: 1, - resource_id: [1u8; 32], - data: vec![1u8], - }; - let p2 = Proposal { - origin_domain_id: 2, - deposit_nonce: 2, - resource_id: [2u8; 32], - data: vec![2u8], - }; - let proposals = vec![p1, p2]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - - // should be false - assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); - }) - } - - #[test] - fn verify_mpc_signature_invalid_message() { - new_test_ext().execute_with(|| { - // generate mpc keypair - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let public = pair.public(); - let message = b"Something important"; - let signature = pair.sign(&message[..]); - - // make sure generated keypair, message and signature are all good - assert!(ecdsa::Pair::verify(&signature, &message[..], &public)); - assert!(!ecdsa::Pair::verify(&signature, b"Something else", &public)); - - // dummy proposals - let p1 = Proposal { - origin_domain_id: 1, - deposit_nonce: 1, - resource_id: [1u8; 32], - data: vec![1u8], - }; - let p2 = Proposal { - origin_domain_id: 2, - deposit_nonce: 2, - resource_id: [2u8; 32], - data: vec![2u8], - }; - let proposals = vec![p1, p2]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - - // verify non matched signature against proposal list, should be false - assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); - }) - } - - #[test] - fn verify_mpc_signature_valid_message_unmatched_mpc() { - new_test_ext().execute_with(|| { - // generate the signing keypair - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - - // set mpc address to another random key - let test_mpc_addr: MpcAddress = MpcAddress([7u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_eq!(MpcAddr::::get(), test_mpc_addr); - - // dummy proposals - let p1 = Proposal { - origin_domain_id: 1, - deposit_nonce: 1, - resource_id: [1u8; 32], - data: vec![1u8], - }; - let p2 = Proposal { - origin_domain_id: 2, - deposit_nonce: 2, - resource_id: [2u8; 32], - data: vec![2u8], - }; - let proposals = vec![p1, p2]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - - // sign final message using generated prikey - let signature = pair.sign_prehashed(&final_message); - - // verify signature, should be false because the signing address != mpc address - assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); - }) - } - - #[test] - fn verify_mpc_signature_valid_message_valid_signature() { - new_test_ext().execute_with(|| { - // generate mpc keypair - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); - - // set mpc address to generated keypair's address - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_eq!(MpcAddr::::get(), test_mpc_addr); - - // dummy proposals - let p1 = Proposal { - origin_domain_id: 1, - deposit_nonce: 1, - resource_id: [1u8; 32], - data: vec![1u8], - }; - let p2 = Proposal { - origin_domain_id: 2, - deposit_nonce: 2, - resource_id: [2u8; 32], - data: vec![2u8], - }; - let proposals = vec![p1, p2]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - - // sign final message using generated mpc prikey - // `pari.sign` will hash the final message into blake2_256 then sign it, so use - // sign_prehashed here - let signature = pair.sign_prehashed(&final_message); - - // verify signature, should be true - assert!(SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); - }) - } - - #[test] - fn deposit_native_asset_should_work() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 1_000_000_000_000u128; // 1 with 12 decimals - let amount = 200_000_000_000_000u128; // 200 with 12 decimals - let final_amount_in_deposit_event = 199_000_000_000_000_000_000; // 200 - 1 then adjust to 18 decimals - - assert_ok!(SygmaBridge::register_domain( + assert!(!IsPaused::::get(DEST_DOMAIN_ID)); + }) + } + + #[test] + fn verify_mpc_signature_invalid_signature() { + new_test_ext().execute_with(|| { + let signature = vec![1u8]; + + // dummy proposals + let p1 = Proposal { + origin_domain_id: 1, + deposit_nonce: 1, + resource_id: [1u8; 32], + data: vec![1u8], + }; + let p2 = Proposal { + origin_domain_id: 2, + deposit_nonce: 2, + resource_id: [2u8; 32], + data: vec![2u8], + }; + let proposals = vec![p1, p2]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + + // should be false + assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); + }) + } + + #[test] + fn verify_mpc_signature_invalid_message() { + new_test_ext().execute_with(|| { + // generate mpc keypair + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + + // make sure generated keypair, message and signature are all good + assert!(ecdsa::Pair::verify(&signature, &message[..], &public)); + assert!(!ecdsa::Pair::verify(&signature, b"Something else", &public)); + + // dummy proposals + let p1 = Proposal { + origin_domain_id: 1, + deposit_nonce: 1, + resource_id: [1u8; 32], + data: vec![1u8], + }; + let p2 = Proposal { + origin_domain_id: 2, + deposit_nonce: 2, + resource_id: [2u8; 32], + data: vec![2u8], + }; + let proposals = vec![p1, p2]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + + // verify non matched signature against proposal list, should be false + assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); + }) + } + + #[test] + fn verify_mpc_signature_valid_message_unmatched_mpc() { + new_test_ext().execute_with(|| { + // generate the signing keypair + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + + // set mpc address to another random key + let test_mpc_addr: MpcAddress = MpcAddress([7u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_eq!(MpcAddr::::get(), test_mpc_addr); + + // dummy proposals + let p1 = Proposal { + origin_domain_id: 1, + deposit_nonce: 1, + resource_id: [1u8; 32], + data: vec![1u8], + }; + let p2 = Proposal { + origin_domain_id: 2, + deposit_nonce: 2, + resource_id: [2u8; 32], + data: vec![2u8], + }; + let proposals = vec![p1, p2]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + + // sign final message using generated prikey + let signature = pair.sign_prehashed(&final_message); + + // verify signature, should be false because the signing address != mpc address + assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); + }) + } + + #[test] + fn verify_mpc_signature_valid_message_valid_signature() { + new_test_ext().execute_with(|| { + // generate mpc keypair + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); + + // set mpc address to generated keypair's address + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_eq!(MpcAddr::::get(), test_mpc_addr); + + // dummy proposals + let p1 = Proposal { + origin_domain_id: 1, + deposit_nonce: 1, + resource_id: [1u8; 32], + data: vec![1u8], + }; + let p2 = Proposal { + origin_domain_id: 2, + deposit_nonce: 2, + resource_id: [2u8; 32], + data: vec![2u8], + }; + let proposals = vec![p1, p2]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + + // sign final message using generated mpc prikey + // `pari.sign` will hash the final message into blake2_256 then sign it, so use + // sign_prehashed here + let signature = pair.sign_prehashed(&final_message); + + // verify signature, should be true + assert!(SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); + }) + } + + #[test] + fn deposit_native_asset_should_work() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 1_000_000_000_000u128; // 1 with 12 decimals + let amount = 200_000_000_000_000u128; // 200 with 12 decimals + let final_amount_in_deposit_event = 199_000_000_000_000_000_000; // 200 - 1 then adjust to 18 decimals + + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -1305,123 +1310,123 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount - fee - ); - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - deposit_nonce: 0, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - final_amount_in_deposit_event, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - fee_amount: fee, - fee_asset_id: NativeLocation::get().into(), - }), - ]); - }) - } - - #[test] - fn hex_zero_padding_32_test() { - new_test_ext().execute_with(|| { - assert_eq!( - SygmaBridge::hex_zero_padding_32(100).to_vec(), - vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 100 - ] - ); - let recipient = String::from("0x95ECF5ae000e0fe0e0dE63aDE9b7D82a372038b4"); - assert_eq!( - SygmaBridge::hex_zero_padding_32(recipient.len() as u128).to_vec(), - vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 42 - ] - ); - }) - } - - #[test] - fn create_deposit_data_test() { - new_test_ext().execute_with(|| { - let recipient = b"0x95ECF5ae000e0fe0e0dE63aDE9b7D82a372038b4".to_vec(); - let data = SygmaBridge::create_deposit_data(100, recipient); - // 32 + 32 + 42 - assert_eq!(data.len(), 106); - assert_eq!( - data.to_vec(), - vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 48, 120, 57, 53, 69, 67, 70, - 53, 97, 101, 48, 48, 48, 101, 48, 102, 101, 48, 101, 48, 100, 69, 54, 51, - 97, 68, 69, 57, 98, 55, 68, 56, 50, 97, 51, 55, 50, 48, 51, 56, 98, 52 - ] - ); - }) - } - - #[test] - fn deposit_foreign_asset_should_work() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 100u128; - let amount = 200u128; - - assert_ok!(SygmaBasicFeeHandler::set_fee( + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + deposit_nonce: 0, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + final_amount_in_deposit_event, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + fee_amount: fee, + fee_asset_id: NativeLocation::get().into(), + }), + ]); + }) + } + + #[test] + fn hex_zero_padding_32_test() { + new_test_ext().execute_with(|| { + assert_eq!( + SygmaBridge::hex_zero_padding_32(100).to_vec(), + vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 100, + ] + ); + let recipient = String::from("0x95ECF5ae000e0fe0e0dE63aDE9b7D82a372038b4"); + assert_eq!( + SygmaBridge::hex_zero_padding_32(recipient.len() as u128).to_vec(), + vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 42, + ] + ); + }) + } + + #[test] + fn create_deposit_data_test() { + new_test_ext().execute_with(|| { + let recipient = b"0x95ECF5ae000e0fe0e0dE63aDE9b7D82a372038b4".to_vec(); + let data = SygmaBridge::create_deposit_data(100, recipient); + // 32 + 32 + 42 + assert_eq!(data.len(), 106); + assert_eq!( + data.to_vec(), + vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 48, 120, 57, 53, 69, 67, 70, + 53, 97, 101, 48, 48, 48, 101, 48, 102, 101, 48, 101, 48, 100, 69, 54, 51, + 97, 68, 69, 57, 98, 55, 68, 56, 50, 97, 51, 55, 50, 48, 51, 56, 98, 52, + ] + ); + }) + } + + #[test] + fn deposit_foreign_asset_should_work() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 100u128; + let amount = 200u128; + + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(UsdtLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(UsdtLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // Register foreign asset (USDT) with asset id 0 - assert_ok!( as FungibleCerate< + // Register foreign asset (USDT) with asset id 0 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some USDT to ALICE for test - assert_ok!(Assets::mint( + // Mint some USDT to ALICE for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), ALICE, ENDOWED_BALANCE, )); - assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(UsdtLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -1432,67 +1437,67 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE - amount); - // USDT in the mock runtime has been configured as the reserved token, so the corresponding account should hold the deposit balance - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ) - ), - amount - fee - ); - assert_eq!(Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), fee); - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdtResourceId::get(), - deposit_nonce: 0, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - amount - fee, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdtResourceId::get(), - fee_amount: fee, - fee_asset_id: UsdtLocation::get().into(), - }), - ]); - }) - } - - #[test] - fn deposit_unbounded_asset_should_fail() { - new_test_ext().execute_with(|| { - let unbounded_asset_location = MultiLocation::new(1, X1(GeneralIndex(123))); - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 100u128; - let amount = 200u128; - - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBasicFeeHandler::set_fee( + // Check balances + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE - amount); + // USDT in the mock runtime has been configured as the reserved token, so the corresponding account should hold the deposit balance + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + amount - fee + ); + assert_eq!(Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), fee); + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: UsdtResourceId::get(), + deposit_nonce: 0, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + amount - fee, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: UsdtResourceId::get(), + fee_amount: fee, + fee_asset_id: UsdtLocation::get().into(), + }), + ]); + }) + } + + #[test] + fn deposit_unbounded_asset_should_fail() { + new_test_ext().execute_with(|| { + let unbounded_asset_location = MultiLocation::new(1, X1(GeneralIndex(123))); + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 100u128; + let amount = 200u128; + + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(unbounded_asset_location.into()), fee )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(unbounded_asset_location), Fungible(amount)).into()), @@ -1506,34 +1511,34 @@ pub mod pallet { ), bridge::Error::::AssetNotBound ); - }) - } - - #[test] - fn deposit_to_unrecognized_dest_should_fail() { - new_test_ext().execute_with(|| { - let invalid_dest = MultiLocation::new( - 0, - X2(GeneralIndex(0), slice_to_generalkey(b"ethereum recipient")), - ); - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 100u128; - let amount = 200u128; + }) + } + + #[test] + fn deposit_to_unrecognized_dest_should_fail() { + new_test_ext().execute_with(|| { + let invalid_dest = MultiLocation::new( + 0, + X2(GeneralIndex(0), slice_to_generalkey(b"ethereum recipient")), + ); + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 100u128; + let amount = 200u128; - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1541,21 +1546,21 @@ pub mod pallet { ), bridge::Error::::ExtractDestDataFailed ); - }) - } + }) + } - #[test] - fn deposit_without_fee_set_should_fail() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let amount = 200u128; - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBridge::register_domain( + #[test] + fn deposit_without_fee_set_should_fail() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let amount = 200u128; + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1569,35 +1574,35 @@ pub mod pallet { ), bridge::Error::::MissingFeeConfig ); - }) - } + }) + } - #[test] - fn deposit_less_than_fee_should_fail() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 200u128; - let amount = 100u128; + #[test] + fn deposit_less_than_fee_should_fail() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 200u128; + let amount = 100u128; - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1611,41 +1616,41 @@ pub mod pallet { ), bridge::Error::::FeeTooExpensive ); - }) - } + }) + } - #[test] - fn deposit_when_bridge_paused_should_fail() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 100u128; - let amount = 200u128; + #[test] + fn deposit_when_bridge_paused_should_fail() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 100u128; + let amount = 200u128; - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - // register domain - assert_ok!(SygmaBridge::register_domain( + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // set mpc address will also unpause all bridges - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + // set mpc address will also unpause all bridges + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // Pause bridge again - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - // Should failed - assert_noop!( + // Pause bridge again + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + // Should failed + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1659,10 +1664,10 @@ pub mod pallet { ), bridge::Error::::BridgePaused ); - // Unpause bridge - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - // Should success - assert_ok!(SygmaBridge::deposit( + // Unpause bridge + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + // Should success + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -1673,22 +1678,22 @@ pub mod pallet { ) }), )); - }) - } + }) + } - #[test] - fn deposit_without_mpc_set_should_fail() { - new_test_ext().execute_with(|| { - let fee = 200u128; - let amount = 100u128; + #[test] + fn deposit_without_mpc_set_should_fail() { + new_test_ext().execute_with(|| { + let fee = 200u128; + let amount = 100u128; - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1702,101 +1707,101 @@ pub mod pallet { ), bridge::Error::::MissingMpcAddress ); - }) - } - - #[test] - fn retry_bridge() { - new_test_ext().execute_with(|| { - // should be access denied SINCE Alice does not have permission to retry - assert_noop!( + }) + } + + #[test] + fn retry_bridge() { + new_test_ext().execute_with(|| { + // should be access denied SINCE Alice does not have permission to retry + assert_noop!( SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - // Grant ALICE the access of `retry` - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access of `retry` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"retry".to_vec(), ALICE )); - // mpc address is missing, should fail - assert_noop!( + // mpc address is missing, should fail + assert_noop!( SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID), bridge::Error::::MissingMpcAddress ); - // set mpc address - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBridge::register_domain( + // set mpc address + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // pause bridge after set mpc address and retry, should fail - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert_noop!( + // pause bridge after set mpc address and retry, should fail + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert_noop!( SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID), bridge::Error::::BridgePaused ); - // unpause bridge - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(!IsPaused::::get(DEST_DOMAIN_ID)); - - // retry again, should work - assert_ok!(SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Retry { - deposit_on_block_height: 1234567u128, - dest_domain_id: DEST_DOMAIN_ID, - sender: ALICE, - })]); - }) - } - - #[test] - fn proposal_execution_should_work() { - new_test_ext().execute_with(|| { - // mpc address is missing, should fail - assert_noop!( + // unpause bridge + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(!IsPaused::::get(DEST_DOMAIN_ID)); + + // retry again, should work + assert_ok!(SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Retry { + deposit_on_block_height: 1234567u128, + dest_domain_id: DEST_DOMAIN_ID, + sender: ALICE, + })]); + }) + } + + #[test] + fn proposal_execution_should_work() { + new_test_ext().execute_with(|| { + // mpc address is missing, should fail + assert_noop!( SygmaBridge::execute_proposal(Origin::signed(ALICE), vec![], vec![]), bridge::Error::::MissingMpcAddress, ); - // set mpc address to generated keypair's address - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_eq!(MpcAddr::::get(), test_mpc_addr); - // register domain - assert_ok!(SygmaBridge::register_domain( + // set mpc address to generated keypair's address + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_eq!(MpcAddr::::get(), test_mpc_addr); + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // Generate an evil key - let (evil_pair, _): (ecdsa::Pair, _) = Pair::generate(); + // Generate an evil key + let (evil_pair, _): (ecdsa::Pair, _) = Pair::generate(); - // Deposit some native asset in advance - let fee = 1_000_000_000_000u128; - let amount: u128 = 200_000_000_000_000u128; - assert_ok!(SygmaBasicFeeHandler::set_fee( + // Deposit some native asset in advance + let fee = 1_000_000_000_000u128; + let amount: u128 = 200_000_000_000_000u128; + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -1808,13 +1813,13 @@ pub mod pallet { }), )); - // Register foreign asset (USDT) with asset id 0 - assert_ok!( as FungibleCerate< + // Register foreign asset (USDT) with asset id 0 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint 400 USDT to liquidity holder for test - assert_ok!(Assets::mint( + // Mint 400 USDT to liquidity holder for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), AccountId::new( @@ -1823,127 +1828,127 @@ pub mod pallet { ), 400_000_000_000_000, )); - // alice deposit 200 - 1 token fee native token, so the native token holder should have 199 tokens - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 199_000_000_000_000 - ); - // USDT liquidity holder should have 400 USDT at this moment - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ) - ), - 400_000_000_000_000 - ); - - // Generate proposals - // amount is in 18 decimal 0.000200000000000000, will be convert to 12 decimal - // 0.000200000000 - let valid_native_transfer_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 1, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - // amount is in 18 decimal 0.000200000000000000, will be convert to 18 decimal - // 0.000200000000000000 - let valid_usdt_transfer_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 2, - resource_id: UsdtResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let invalid_depositnonce_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 2, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let invalid_domainid_proposal = Proposal { - origin_domain_id: 2, - deposit_nonce: 3, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let invalid_resourceid_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 3, - resource_id: [2u8; 32], - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let invalid_recipient_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 3, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data(amount, b"invalid recipient".to_vec()), - }; - let empty_data_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 3, - resource_id: UsdtResourceId::get(), - data: vec![], - }; - - let proposals = vec![ - valid_native_transfer_proposal, - valid_usdt_transfer_proposal, - invalid_depositnonce_proposal, - invalid_domainid_proposal, - invalid_resourceid_proposal, - invalid_recipient_proposal, - empty_data_proposal, - ]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - let proposals_with_valid_signature = pair.sign_prehashed(&final_message); - let proposals_with_bad_signature = evil_pair.sign_prehashed(&final_message); - - // Should failed if dest domain 1 bridge paused - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(IsPaused::::get(DEST_DOMAIN_ID)); - assert_ok!(SygmaBridge::execute_proposal( + // alice deposit 200 - 1 token fee native token, so the native token holder should have 199 tokens + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 199_000_000_000_000 + ); + // USDT liquidity holder should have 400 USDT at this moment + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + 400_000_000_000_000 + ); + + // Generate proposals + // amount is in 18 decimal 0.000200000000000000, will be convert to 12 decimal + // 0.000200000000 + let valid_native_transfer_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 1, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + // amount is in 18 decimal 0.000200000000000000, will be convert to 18 decimal + // 0.000200000000000000 + let valid_usdt_transfer_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 2, + resource_id: UsdtResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let invalid_depositnonce_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 2, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let invalid_domainid_proposal = Proposal { + origin_domain_id: 2, + deposit_nonce: 3, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let invalid_resourceid_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 3, + resource_id: [2u8; 32], + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let invalid_recipient_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 3, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data(amount, b"invalid recipient".to_vec()), + }; + let empty_data_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 3, + resource_id: UsdtResourceId::get(), + data: vec![], + }; + + let proposals = vec![ + valid_native_transfer_proposal, + valid_usdt_transfer_proposal, + invalid_depositnonce_proposal, + invalid_domainid_proposal, + invalid_resourceid_proposal, + invalid_recipient_proposal, + empty_data_proposal, + ]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + let proposals_with_valid_signature = pair.sign_prehashed(&final_message); + let proposals_with_bad_signature = evil_pair.sign_prehashed(&final_message); + + // Should failed if dest domain 1 bridge paused + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(IsPaused::::get(DEST_DOMAIN_ID)); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals.clone(), proposals_with_valid_signature.encode() )); - // should emit FailedHandlerExecution event - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::FailedHandlerExecution { - error: vec![66, 114, 105, 100, 103, 101, 80, 97, 117, 115, 101, 100], - origin_domain_id: 1, - deposit_nonce: 3, - }, - )]); - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - - assert_noop!( + // should emit FailedHandlerExecution event + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::FailedHandlerExecution { + error: vec![66, 114, 105, 100, 103, 101, 80, 97, 117, 115, 101, 100], + origin_domain_id: 1, + deposit_nonce: 3, + }, + )]); + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + + assert_noop!( SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals.clone(), @@ -1951,294 +1956,294 @@ pub mod pallet { ), bridge::Error::::BadMpcSignature, ); - assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE); - assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), 0); - assert!(SygmaBridge::verify_by_mpc_address( - final_message, - proposals_with_valid_signature.encode() - )); - assert_ok!(SygmaBridge::execute_proposal( + assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE); + assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), 0); + assert!(SygmaBridge::verify_by_mpc_address( + final_message, + proposals_with_valid_signature.encode(), + )); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals, proposals_with_valid_signature.encode(), )); - // proposal amount is in 18 decimal 0.000200000000000000, will be convert to 12 - // decimal 0.000200000000(200000000) because native asset is defined in 12 decimal - assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE + 200000000); - // usdt is defined in 18 decimal so that converted amount is the same as in proposal - assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), amount); - - // liquidity holder accounts balance after proposals execution - // 199 - 0.0002 native token is 198.999800000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 199_000_000_000_000 - 200_000_000 - ); - // 400 USDT after transferring out the USDT proposal, should remain 200 USDT - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ) - ), - 200_000_000_000_000 - ); - }) - } - - #[test] - fn get_bridge_pause_status() { - new_test_ext().execute_with(|| { - assert!(!SygmaBridge::is_paused(DEST_DOMAIN_ID)); - - // set mpc address - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // register domain - assert_ok!(SygmaBridge::register_domain( + // proposal amount is in 18 decimal 0.000200000000000000, will be convert to 12 + // decimal 0.000200000000(200000000) because native asset is defined in 12 decimal + assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE + 200000000); + // usdt is defined in 18 decimal so that converted amount is the same as in proposal + assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), amount); + + // liquidity holder accounts balance after proposals execution + // 199 - 0.0002 native token is 198.999800000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 199_000_000_000_000 - 200_000_000 + ); + // 400 USDT after transferring out the USDT proposal, should remain 200 USDT + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + 200_000_000_000_000 + ); + }) + } + + #[test] + fn get_bridge_pause_status() { + new_test_ext().execute_with(|| { + assert!(!SygmaBridge::is_paused(DEST_DOMAIN_ID)); + + // set mpc address + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // pause bridge - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(SygmaBridge::is_paused(DEST_DOMAIN_ID)); + // pause bridge + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(SygmaBridge::is_paused(DEST_DOMAIN_ID)); - // unpause bridge - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(!SygmaBridge::is_paused(DEST_DOMAIN_ID)); - }) - } + // unpause bridge + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(!SygmaBridge::is_paused(DEST_DOMAIN_ID)); + }) + } - #[test] - fn access_control() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + #[test] + fn access_control() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_noop!( + assert_noop!( SygmaBridge::set_mpc_address(Some(ALICE).into(), test_mpc_addr), bridge::Error::::AccessDenied ); - assert_noop!( + assert_noop!( SygmaBridge::pause_bridge(Some(BOB).into(), DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - assert_noop!( + assert_noop!( SygmaBridge::unpause_bridge(Some(BOB).into(), DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - // Grant ALICE the access of `set_mpc_address` - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access of `set_mpc_address` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"set_mpc_address".to_vec(), ALICE )); - // Grant BOB the access of `pause_bridge` and `unpause_bridge` - assert_ok!(AccessSegregator::grant_access( + // Grant BOB the access of `pause_bridge` and `unpause_bridge` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"pause_bridge".to_vec(), BOB )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unpause_bridge".to_vec(), BOB )); - // BOB set mpc address should still failed - assert_noop!( + // BOB set mpc address should still failed + assert_noop!( SygmaBridge::set_mpc_address(Some(BOB).into(), test_mpc_addr), bridge::Error::::AccessDenied ); - // ALICE set mpc address should work - assert_ok!(SygmaBridge::set_mpc_address(Some(ALICE).into(), test_mpc_addr)); - // register domain - assert_ok!(SygmaBridge::register_domain( + // ALICE set mpc address should work + assert_ok!(SygmaBridge::set_mpc_address(Some(ALICE).into(), test_mpc_addr)); + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // ALICE pause&unpause bridge should still failed - assert_noop!( + // ALICE pause&unpause bridge should still failed + assert_noop!( SygmaBridge::pause_bridge(Some(ALICE).into(), DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - assert_noop!( + assert_noop!( SygmaBridge::unpause_bridge(Some(ALICE).into(), DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - // BOB pause&unpause bridge should work - assert_ok!(SygmaBridge::pause_bridge(Some(BOB).into(), DEST_DOMAIN_ID)); - assert_ok!(SygmaBridge::unpause_bridge(Some(BOB).into(), DEST_DOMAIN_ID)); - }) - } - - #[test] - fn multi_domain_test() { - new_test_ext().execute_with(|| { - // root register domainID 1 with chainID 0, should be ok - assert_ok!(SygmaBridge::register_domain(Origin::root(), 1u8, U256::from(0))); - - // set mpc address - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - - // alice register domainID 1 with chainID 1, should raise error AccessDenied - assert_noop!( + // BOB pause&unpause bridge should work + assert_ok!(SygmaBridge::pause_bridge(Some(BOB).into(), DEST_DOMAIN_ID)); + assert_ok!(SygmaBridge::unpause_bridge(Some(BOB).into(), DEST_DOMAIN_ID)); + }) + } + + #[test] + fn multi_domain_test() { + new_test_ext().execute_with(|| { + // root register domainID 1 with chainID 0, should be ok + assert_ok!(SygmaBridge::register_domain(Origin::root(), 1u8, U256::from(0))); + + // set mpc address + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + + // alice register domainID 1 with chainID 1, should raise error AccessDenied + assert_noop!( SygmaBridge::register_domain(Origin::from(Some(ALICE)), 1u8, U256::from(1)), Error::::AccessDenied ); - // Grant ALICE the access of `register_domain` - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access of `register_domain` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"register_domain".to_vec(), ALICE )); - // alice register domainID 1 with chainID 1, should be ok - assert_ok!(SygmaBridge::register_domain( + // alice register domainID 1 with chainID 1, should be ok + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), 1u8, U256::from(1) )); - // should emit RegisterDestDomain event - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::RegisterDestDomain { - sender: ALICE, - domain_id: 1, - chain_id: U256::from(1), - }, - )]); - // storage check - assert!(DestDomainIds::::get(1u8)); - assert_eq!(DestChainIds::::get(1u8).unwrap(), U256::from(1)); - - // alice unregister domainID 1 with chainID 0, should raise error AccessDenied - assert_noop!( + // should emit RegisterDestDomain event + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::RegisterDestDomain { + sender: ALICE, + domain_id: 1, + chain_id: U256::from(1), + }, + )]); + // storage check + assert!(DestDomainIds::::get(1u8)); + assert_eq!(DestChainIds::::get(1u8).unwrap(), U256::from(1)); + + // alice unregister domainID 1 with chainID 0, should raise error AccessDenied + assert_noop!( SygmaBridge::unregister_domain(Origin::from(Some(ALICE)), 1u8, U256::from(0)), Error::::AccessDenied ); - // Grant ALICE the access of `unregister_domain` - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access of `unregister_domain` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unregister_domain".to_vec(), ALICE )); - // alice unregister domainID 1 with chainID 2, should raise error - // DestChainIDNotMatch - assert_noop!( + // alice unregister domainID 1 with chainID 2, should raise error + // DestChainIDNotMatch + assert_noop!( SygmaBridge::unregister_domain(Origin::from(Some(ALICE)), 1u8, U256::from(2)), Error::::DestChainIDNotMatch ); - // alice unregister domainID 2 with chainID 2, should raise error - // DestDomainNotSupported - assert_noop!( + // alice unregister domainID 2 with chainID 2, should raise error + // DestDomainNotSupported + assert_noop!( SygmaBridge::unregister_domain(Origin::from(Some(ALICE)), 2u8, U256::from(2)), Error::::DestDomainNotSupported ); - // alice unregister domainID 1 with chainID 1, should success - assert_ok!(SygmaBridge::unregister_domain( + // alice unregister domainID 1 with chainID 1, should success + assert_ok!(SygmaBridge::unregister_domain( Origin::from(Some(ALICE)), 1u8, U256::from(1) )); - // should emit UnregisterDestDomain event - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::UnregisterDestDomain { - sender: ALICE, - domain_id: 1, - chain_id: U256::from(1), - }, - )]); - - // storage check - // DomainID 1 should not support anymore - assert!(!DestDomainIds::::get(1u8)); - // corresponding chainID should be None since kv not exist anymore - assert!(DestChainIds::::get(1u8).is_none()); - }) - } - - #[test] - fn deposit_with_decimal_converter() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - - // native asset with 12 decimal - let fee_native_asset = 1_000_000_000_000u128; // 1.0 native asset - let amount_native_asset = 123_456_789_123_456u128; // 123.456_789_123_456 - let adjusted_amount_native_asset = 122_456_789_123_456_000_000u128; // amount_native_asset - fee_native_asset then adjust it to 18 decimals - - // usdt asset with 18 decimal - let fee_usdt_asset = 1_000_000_000_000_000_000u128; // 1.0 usdt asset - let amount_usdt_asset = 123_456_789_123_456_789_123u128; // 123.456_789_123_456_789_123 - let adjusted_amount_usdt_asset = 122_456_789_123_456_789_123u128; // amount_usdt_asset - fee_usdt_asset then adjust it to 18 decimals - - // astr asset with 24 decimal - let fee_astr_asset = 1_000_000_000_000_000_000_000_000u128; // 1.0 astr asset - let amount_astr_asset = 123_456_789_123_456_789_123_456_789u128; // 123.456_789_123_456_789_123_456_789 - let adjusted_amount_astr_asset = 122_456_789_123_456_789_123u128; // amount_astr_asset - fee_astr_asset then adjust it to 18 decimals - - // set fees - assert_ok!(SygmaBasicFeeHandler::set_fee( + // should emit UnregisterDestDomain event + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::UnregisterDestDomain { + sender: ALICE, + domain_id: 1, + chain_id: U256::from(1), + }, + )]); + + // storage check + // DomainID 1 should not support anymore + assert!(!DestDomainIds::::get(1u8)); + // corresponding chainID should be None since kv not exist anymore + assert!(DestChainIds::::get(1u8).is_none()); + }) + } + + #[test] + fn deposit_with_decimal_converter() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + + // native asset with 12 decimal + let fee_native_asset = 1_000_000_000_000u128; // 1.0 native asset + let amount_native_asset = 123_456_789_123_456u128; // 123.456_789_123_456 + let adjusted_amount_native_asset = 122_456_789_123_456_000_000u128; // amount_native_asset - fee_native_asset then adjust it to 18 decimals + + // usdt asset with 18 decimal + let fee_usdt_asset = 1_000_000_000_000_000_000u128; // 1.0 usdt asset + let amount_usdt_asset = 123_456_789_123_456_789_123u128; // 123.456_789_123_456_789_123 + let adjusted_amount_usdt_asset = 122_456_789_123_456_789_123u128; // amount_usdt_asset - fee_usdt_asset then adjust it to 18 decimals + + // astr asset with 24 decimal + let fee_astr_asset = 1_000_000_000_000_000_000_000_000u128; // 1.0 astr asset + let amount_astr_asset = 123_456_789_123_456_789_123_456_789u128; // 123.456_789_123_456_789_123_456_789 + let adjusted_amount_astr_asset = 122_456_789_123_456_789_123u128; // amount_astr_asset - fee_astr_asset then adjust it to 18 decimals + + // set fees + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee_native_asset )); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(UsdtLocation::get().into()), fee_usdt_asset )); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(AstrLocation::get().into()), fee_astr_asset )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(UsdtLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(AstrLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // deposit native asset which has 12 decimal - assert_ok!(SygmaBridge::deposit( + // deposit native asset which has 12 decimal + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new( (Concrete(NativeLocation::get()), Fungible(amount_native_asset)).into() @@ -2251,58 +2256,58 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount_native_asset); - // native asset should be reserved so that BridgeAccount should hold it - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount_native_asset - fee_native_asset - ); - // TreasuryAccount is collecting the bridging fee - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee_native_asset); - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - deposit_nonce: 0, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - adjusted_amount_native_asset, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - fee_amount: fee_native_asset, - fee_asset_id: NativeLocation::get().into(), - }), - ]); - - // deposit usdt asset which has 18 decimal - // Register foreign asset (usdt) with asset id 0 - assert_ok!( as FungibleCerate< + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount_native_asset); + // native asset should be reserved so that BridgeAccount should hold it + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount_native_asset - fee_native_asset + ); + // TreasuryAccount is collecting the bridging fee + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee_native_asset); + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + deposit_nonce: 0, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + adjusted_amount_native_asset, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + fee_amount: fee_native_asset, + fee_asset_id: NativeLocation::get().into(), + }), + ]); + + // deposit usdt asset which has 18 decimal + // Register foreign asset (usdt) with asset id 0 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some usdt to ALICE for test - assert_ok!(Assets::mint( + // Mint some usdt to ALICE for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), ALICE, ENDOWED_BALANCE, )); // make sure Alice owns enough funds here - assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); - // deposit - assert_ok!(SygmaBridge::deposit( + // deposit + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(UsdtLocation::get()), Fungible(amount_usdt_asset)).into()), Box::new(MultiLocation { @@ -2313,67 +2318,67 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!( - Assets::balance(UsdtAssetId::get(), &ALICE), - ENDOWED_BALANCE - amount_usdt_asset - ); - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ) - ), - 122_456_789_123_456_789_123 - ); - // TreasuryAccount is collecting the bridging fee - assert_eq!( - Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), - fee_usdt_asset - ); - - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdtResourceId::get(), - deposit_nonce: 1, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - adjusted_amount_usdt_asset, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdtResourceId::get(), - fee_amount: fee_usdt_asset, - fee_asset_id: UsdtLocation::get().into(), - }), - ]); - - // deposit astr asset which has 24 decimal - // Register foreign asset (astr) with asset id 1 - assert_ok!( as FungibleCerate< + // Check balances + assert_eq!( + Assets::balance(UsdtAssetId::get(), &ALICE), + ENDOWED_BALANCE - amount_usdt_asset + ); + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + 122_456_789_123_456_789_123 + ); + // TreasuryAccount is collecting the bridging fee + assert_eq!( + Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), + fee_usdt_asset + ); + + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: UsdtResourceId::get(), + deposit_nonce: 1, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + adjusted_amount_usdt_asset, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: UsdtResourceId::get(), + fee_amount: fee_usdt_asset, + fee_asset_id: UsdtLocation::get().into(), + }), + ]); + + // deposit astr asset which has 24 decimal + // Register foreign asset (astr) with asset id 1 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(AstrAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some astr to ALICE for test - assert_ok!(Assets::mint( + // Mint some astr to ALICE for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(1), ALICE, ENDOWED_BALANCE, )); // make sure Alice owns enough funds here - assert_eq!(Assets::balance(AstrAssetId::get(), &ALICE), ENDOWED_BALANCE); + assert_eq!(Assets::balance(AstrAssetId::get(), &ALICE), ENDOWED_BALANCE); - // deposit - assert_ok!(SygmaBridge::deposit( + // deposit + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(AstrLocation::get()), Fungible(amount_astr_asset)).into()), Box::new(MultiLocation { @@ -2384,64 +2389,65 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!( - Assets::balance(AstrAssetId::get(), &ALICE), - ENDOWED_BALANCE - amount_astr_asset - ); - // astr asset should be reserved so that BridgeAccount should hold it(Astr is not - // defined in ConcrateSygmaAsset) - assert_eq!( - Assets::balance( - AstrAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) - .unwrap() - ) - ), - amount_astr_asset - fee_astr_asset - ); - // TreasuryAccount is collecting the bridging fee - assert_eq!( - Assets::balance(AstrAssetId::get(), TreasuryAccount::get()), - fee_astr_asset - ); - - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: AstrResourceId::get(), - deposit_nonce: 2, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - adjusted_amount_astr_asset, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: AstrResourceId::get(), - fee_amount: fee_astr_asset, - fee_asset_id: AstrLocation::get().into(), - }), - ]); - - // deposit astr asset which has 24 decimal, extreme small amount edge case - let amount_astr_asset_extreme_small_amount = 100_000; // 0.000000000000000000100000 astr - let fee_astr_asset_extreme_small_amount = 1; // 0.000000000000000000000001 astr - assert_ok!(SygmaBasicFeeHandler::set_fee( + // Check balances + assert_eq!( + Assets::balance(AstrAssetId::get(), &ALICE), + ENDOWED_BALANCE - amount_astr_asset + ); + // astr asset should be reserved so that BridgeAccount should hold it(Astr is not + // defined in ConcrateSygmaAsset) + assert_eq!( + Assets::balance( + AstrAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) + .unwrap() + ), + ), + amount_astr_asset - fee_astr_asset + ); + // TreasuryAccount is collecting the bridging fee + assert_eq!( + Assets::balance(AstrAssetId::get(), TreasuryAccount::get()), + fee_astr_asset + ); + + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: AstrResourceId::get(), + deposit_nonce: 2, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + adjusted_amount_astr_asset, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: AstrResourceId::get(), + fee_amount: fee_astr_asset, + fee_asset_id: AstrLocation::get().into(), + }), + ]); + + // deposit astr asset which has 24 decimal, extreme small amount edge case + let amount_astr_asset_extreme_small_amount = 100_000; // 0.000000000000000000100000 astr + let fee_astr_asset_extreme_small_amount = 1; + // 0.000000000000000000000001 astr + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(AstrLocation::get().into()), fee_astr_asset_extreme_small_amount )); - // after decimal conversion from 24 to 18, the final amount will be 0 so that - // decimal conversion will raise error deposit should not work - assert_noop!( + // after decimal conversion from 24 to 18, the final amount will be 0 so that + // decimal conversion will raise error deposit should not work + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new( @@ -2461,41 +2467,42 @@ pub mod pallet { ), bridge::Error::::DecimalConversionFail ); - }) - } - - #[test] - fn proposal_execution_with_decimal_converter() { - new_test_ext().execute_with(|| { - // generate mpc keypair - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); - // set mpc address - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // register domain - assert_ok!(SygmaBridge::register_domain( + }) + } + + #[test] + fn proposal_execution_with_decimal_converter() { + new_test_ext().execute_with(|| { + // generate mpc keypair + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); + // set mpc address + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - let fee = 1_000_000_000_000u128; // 1 token in 12 decimals - let init_deposit = 10_000_000_000_000u128; // 12 token in 12 decimal - assert_ok!(SygmaBasicFeeHandler::set_fee( + let fee = 1_000_000_000_000u128; // 1 token in 12 decimals + let init_deposit = 10_000_000_000_000u128; + // 12 token in 12 decimal + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - // deposit in advance to make sure the native asset has enough funds in - // TransferReserveAccount by doing this, Alice will deposit (half of her native - // asset - fee) into TransferReserveAccount - assert_ok!(SygmaBridge::deposit( + // deposit in advance to make sure the native asset has enough funds in + // TransferReserveAccount by doing this, Alice will deposit (half of her native + // asset - fee) into TransferReserveAccount + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new( (Concrete(NativeLocation::get()), Fungible(ENDOWED_BALANCE / 2)).into() @@ -2508,57 +2515,57 @@ pub mod pallet { ) }), )); - // BridgeAccount should have half of alice native asset - fee - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - ENDOWED_BALANCE / 2 - fee - ); - // TreasuryAccount is collecting the bridging fee - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); - - let bridge_amount = 100_000_000_000_000_000_000; // 100 native with 18 decimals - - // proposal for bridging native asset to alice(native asset is 12 decimal) - let p_native = Proposal { - origin_domain_id: 1, - resource_id: NativeResourceId::get(), - deposit_nonce: 1, - data: SygmaBridge::create_deposit_data( - bridge_amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) - .encode(), - ), - }; - let proposals = vec![p_native]; - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - let signature = pair.sign_prehashed(&final_message); - - // check Alice balance of native asset before executing, should have half of the - // init native asset - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE / 2); - assert_ok!(SygmaBridge::execute_proposal( + // BridgeAccount should have half of alice native asset - fee + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + ENDOWED_BALANCE / 2 - fee + ); + // TreasuryAccount is collecting the bridging fee + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); + + let bridge_amount = 100_000_000_000_000_000_000; // 100 native with 18 decimals + + // proposal for bridging native asset to alice(native asset is 12 decimal) + let p_native = Proposal { + origin_domain_id: 1, + resource_id: NativeResourceId::get(), + deposit_nonce: 1, + data: SygmaBridge::create_deposit_data( + bridge_amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) + .encode(), + ), + }; + let proposals = vec![p_native]; + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + let signature = pair.sign_prehashed(&final_message); + + // check Alice balance of native asset before executing, should have half of the + // init native asset + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE / 2); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals, signature.encode() )); - // check Alice balance of native asset after executing, should have half of the init - // native asset + 100_000_000_000_000(12 decimal) - assert_eq!( - Balances::free_balance(ALICE), - ENDOWED_BALANCE / 2 + 100_000_000_000_000 - ); + // check Alice balance of native asset after executing, should have half of the init + // native asset + 100_000_000_000_000(12 decimal) + assert_eq!( + Balances::free_balance(ALICE), + ENDOWED_BALANCE / 2 + 100_000_000_000_000 + ); - // proposal for bridging usdt asset to alice(usdt asset is 18 decimal) - // Register foreign asset (usdt) with asset id 0 - assert_ok!( as FungibleCerate< + // proposal for bridging usdt asset to alice(usdt asset is 18 decimal) + // Register foreign asset (usdt) with asset id 0 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some USDT to liquidity holder for test - assert_ok!(Assets::mint( + // Mint some USDT to liquidity holder for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), AccountId::new( @@ -2567,53 +2574,53 @@ pub mod pallet { ), ENDOWED_BALANCE, )); - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ) - ), - ENDOWED_BALANCE - ); - - let p_usdt = Proposal { - origin_domain_id: 1, - deposit_nonce: 2, - resource_id: UsdtResourceId::get(), - data: SygmaBridge::create_deposit_data( - bridge_amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) - .encode(), - ), - }; - let proposals_usdt = vec![p_usdt]; - let final_message_usdt = - SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_usdt); - let signature_usdt = pair.sign_prehashed(&final_message_usdt); - - // alice does not have any usdt at this moment - assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), 0); - assert_ok!(SygmaBridge::execute_proposal( + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + ENDOWED_BALANCE + ); + + let p_usdt = Proposal { + origin_domain_id: 1, + deposit_nonce: 2, + resource_id: UsdtResourceId::get(), + data: SygmaBridge::create_deposit_data( + bridge_amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) + .encode(), + ), + }; + let proposals_usdt = vec![p_usdt]; + let final_message_usdt = + SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_usdt); + let signature_usdt = pair.sign_prehashed(&final_message_usdt); + + // alice does not have any usdt at this moment + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), 0); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals_usdt, signature_usdt.encode() )); - // alice should have 100 usdt at this moment (100 usdt with 18 decimals) - assert_eq!( - Assets::balance(UsdtAssetId::get(), &ALICE), - 100_000_000_000_000_000_000 - ); + // alice should have 100 usdt at this moment (100 usdt with 18 decimals) + assert_eq!( + Assets::balance(UsdtAssetId::get(), &ALICE), + 100_000_000_000_000_000_000 + ); - // proposal for bridging astr asset to alice(astr asset is 24 decimal) - // Register foreign asset (astr) with asset id 1 - assert_ok!( as FungibleCerate< + // proposal for bridging astr asset to alice(astr asset is 24 decimal) + // Register foreign asset (astr) with asset id 1 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(AstrAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some astr to BridgeAccount for test because astr is reserved asset for - // testing - assert_ok!(Assets::mint( + // Mint some astr to BridgeAccount for test because astr is reserved asset for + // testing + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(1), AccountId::new( @@ -2622,208 +2629,208 @@ pub mod pallet { ), ENDOWED_BALANCE )); - assert_eq!( - Assets::balance( - AstrAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) - .unwrap() - ) - ), - ENDOWED_BALANCE - ); - - let p_astr = Proposal { - origin_domain_id: 1, - deposit_nonce: 3, - resource_id: AstrResourceId::get(), - data: SygmaBridge::create_deposit_data( - bridge_amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) - .encode(), - ), - }; - let proposals_astr = vec![p_astr]; - let final_message_astr = - SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_astr); - let signature_astr = pair.sign_prehashed(&final_message_astr); - - // alice does not have any astr at this moment - assert_eq!(Assets::balance(AstrAssetId::get(), &ALICE), 0); - assert_ok!(SygmaBridge::execute_proposal( + assert_eq!( + Assets::balance( + AstrAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) + .unwrap() + ), + ), + ENDOWED_BALANCE + ); + + let p_astr = Proposal { + origin_domain_id: 1, + deposit_nonce: 3, + resource_id: AstrResourceId::get(), + data: SygmaBridge::create_deposit_data( + bridge_amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) + .encode(), + ), + }; + let proposals_astr = vec![p_astr]; + let final_message_astr = + SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_astr); + let signature_astr = pair.sign_prehashed(&final_message_astr); + + // alice does not have any astr at this moment + assert_eq!(Assets::balance(AstrAssetId::get(), &ALICE), 0); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals_astr, signature_astr.encode() )); - // alice should have 100 astr at this moment (100 astr with 24 decimals) - assert_eq!( - Assets::balance(AstrAssetId::get(), &ALICE), - 100_000_000_000_000_000_000_000_000 - ); - - // extreme small amount edge case - let extreme_small_bridge_amount = 100_000; // 0.000000000000100000 native asset with 18 decimals - // proposal for bridging native asset to alice(native asset is 12 decimal) - let p_native_extreme = Proposal { - origin_domain_id: 1, - resource_id: NativeResourceId::get(), - deposit_nonce: 4, - data: SygmaBridge::create_deposit_data( - extreme_small_bridge_amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) - .encode(), - ), - }; - let proposals_extreme = vec![p_native_extreme]; - let final_message_extreme = - SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_extreme); - let signature_extreme = pair.sign_prehashed(&final_message_extreme); - - // execute_proposal extrinsic should work but it will actually failed at decimal - // conversion step because 0.000000000000100000 in 18 decimal converts to 12 decimal - // would be 0.000000000000 which is 0 - assert_ok!(SygmaBridge::execute_proposal( + // alice should have 100 astr at this moment (100 astr with 24 decimals) + assert_eq!( + Assets::balance(AstrAssetId::get(), &ALICE), + 100_000_000_000_000_000_000_000_000 + ); + + // extreme small amount edge case + let extreme_small_bridge_amount = 100_000; // 0.000000000000100000 native asset with 18 decimals + // proposal for bridging native asset to alice(native asset is 12 decimal) + let p_native_extreme = Proposal { + origin_domain_id: 1, + resource_id: NativeResourceId::get(), + deposit_nonce: 4, + data: SygmaBridge::create_deposit_data( + extreme_small_bridge_amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) + .encode(), + ), + }; + let proposals_extreme = vec![p_native_extreme]; + let final_message_extreme = + SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_extreme); + let signature_extreme = pair.sign_prehashed(&final_message_extreme); + + // execute_proposal extrinsic should work but it will actually failed at decimal + // conversion step because 0.000000000000100000 in 18 decimal converts to 12 decimal + // would be 0.000000000000 which is 0 + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals_extreme, signature_extreme.encode() )); - // should emit FailedHandlerExecution event - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::FailedHandlerExecution { - error: vec![ - 68, 101, 99, 105, 109, 97, 108, 67, 111, 110, 118, 101, 114, 115, 105, - 111, 110, 70, 97, 105, 108, - ], - origin_domain_id: 1, - deposit_nonce: 4, - }, - )]); - }) - } - - #[test] - fn unpause_all_domains_test() { - new_test_ext().execute_with(|| { - // Grant ALICE the access of `register_domain` - assert_ok!(AccessSegregator::grant_access( + // should emit FailedHandlerExecution event + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::FailedHandlerExecution { + error: vec![ + 68, 101, 99, 105, 109, 97, 108, 67, 111, 110, 118, 101, 114, 115, 105, + 111, 110, 70, 97, 105, 108, + ], + origin_domain_id: 1, + deposit_nonce: 4, + }, + )]); + }) + } + + #[test] + fn unpause_all_domains_test() { + new_test_ext().execute_with(|| { + // Grant ALICE the access of `register_domain` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"register_domain".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"pause_bridge".to_vec(), ALICE )); - // alice register some domains - assert_ok!(SygmaBridge::register_domain( + // alice register some domains + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), 1u8, U256::from(1) )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), 2u8, U256::from(2) )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), 3u8, U256::from(3) )); - // pause all - assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 1)); - assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 2)); - assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 3)); + // pause all + assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 1)); + assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 2)); + assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 3)); - // double check if they are all paused - assert!(SygmaBridge::is_paused(1)); - assert!(SygmaBridge::is_paused(2)); - assert!(SygmaBridge::is_paused(3)); + // double check if they are all paused + assert!(SygmaBridge::is_paused(1)); + assert!(SygmaBridge::is_paused(2)); + assert!(SygmaBridge::is_paused(3)); - SygmaBridge::unpause_all_domains(); + SygmaBridge::unpause_all_domains(); - // all domains should be unpaused now - assert!(!SygmaBridge::is_paused(1)); - assert!(!SygmaBridge::is_paused(2)); - assert!(!SygmaBridge::is_paused(3)); - }) - } + // all domains should be unpaused now + assert!(!SygmaBridge::is_paused(1)); + assert!(!SygmaBridge::is_paused(2)); + assert!(!SygmaBridge::is_paused(3)); + }) + } - #[test] - fn setup_order_test() { - new_test_ext().execute_with(|| { - // Make sure mpc address is not set - let default_addr: MpcAddress = MpcAddress::default(); - assert_eq!(MpcAddr::::get(), default_addr); + #[test] + fn setup_order_test() { + new_test_ext().execute_with(|| { + // Make sure mpc address is not set + let default_addr: MpcAddress = MpcAddress::default(); + assert_eq!(MpcAddr::::get(), default_addr); - // Grant ALICE the access admin extrinsics - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access admin extrinsics + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"register_domain".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unregister_domain".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"pause_bridge".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unpause_bridge".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"retry".to_vec(), ALICE )); - // alice setup bridges without mpc address setup - assert_ok!(SygmaBridge::register_domain( + // alice setup bridges without mpc address setup + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::unregister_domain( + assert_ok!(SygmaBridge::unregister_domain( Origin::from(Some(ALICE)), DEST_DOMAIN_ID, U256::from(1) )); - // register it back - assert_ok!(SygmaBridge::register_domain( + // register it back + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::pause_bridge(Origin::from(Some(ALICE)), 1u8)); - assert_ok!(SygmaBridge::unpause_bridge(Origin::from(Some(ALICE)), 1u8)); - // pause domain 2 again to see if mpc address setup will unpause it - assert_ok!(SygmaBridge::pause_bridge(Origin::from(Some(ALICE)), 1u8)); + assert_ok!(SygmaBridge::pause_bridge(Origin::from(Some(ALICE)), 1u8)); + assert_ok!(SygmaBridge::unpause_bridge(Origin::from(Some(ALICE)), 1u8)); + // pause domain 2 again to see if mpc address setup will unpause it + assert_ok!(SygmaBridge::pause_bridge(Origin::from(Some(ALICE)), 1u8)); - // double check if it's paused - assert!(SygmaBridge::is_paused(1)); + // double check if it's paused + assert!(SygmaBridge::is_paused(1)); - // retry should not work here, should raise MissingMpcAddress - assert_noop!( + // retry should not work here, should raise MissingMpcAddress + assert_noop!( SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID), bridge::Error::::MissingMpcAddress ); - // deposit should not work, should raise MissingMpcAddress - assert_noop!( + // deposit should not work, should raise MissingMpcAddress + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(AstrLocation::get()), Fungible(100)).into()), @@ -2837,45 +2844,45 @@ pub mod pallet { ), bridge::Error::::MissingMpcAddress ); - // proposal execution should not work either, should raise MissingMpcAddress - assert_noop!( + // proposal execution should not work either, should raise MissingMpcAddress + assert_noop!( SygmaBridge::execute_proposal(Origin::signed(ALICE), vec![], vec![]), bridge::Error::::MissingMpcAddress, ); - // set mpc address to generated keypair's address - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_eq!(MpcAddr::::get(), test_mpc_addr); + // set mpc address to generated keypair's address + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_eq!(MpcAddr::::get(), test_mpc_addr); - // double check if it's unpause now - assert!(!SygmaBridge::is_paused(1)); + // double check if it's unpause now + assert!(!SygmaBridge::is_paused(1)); - // retry again, should work - assert_ok!(SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Retry { - deposit_on_block_height: 1234567u128, - dest_domain_id: DEST_DOMAIN_ID, - sender: ALICE, - })]); + // retry again, should work + assert_ok!(SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Retry { + deposit_on_block_height: 1234567u128, + dest_domain_id: DEST_DOMAIN_ID, + sender: ALICE, + })]); - // deposit should work now - let fee = 1_000_000_000_000u128; - let amount = 200_000_000_000_000u128; - assert_ok!(SygmaBasicFeeHandler::set_fee( + // deposit should work now + let fee = 1_000_000_000_000u128; + let amount = 200_000_000_000_000u128; + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -2886,71 +2893,71 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount - fee - ); - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); - - // proposal execution should work - let valid_native_transfer_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 1, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let proposals = vec![valid_native_transfer_proposal]; - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - let proposals_with_valid_signature = pair.sign_prehashed(&final_message); - assert_ok!(SygmaBridge::execute_proposal( + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); + + // proposal execution should work + let valid_native_transfer_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 1, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let proposals = vec![valid_native_transfer_proposal]; + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + let proposals_with_valid_signature = pair.sign_prehashed(&final_message); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals, proposals_with_valid_signature.encode(), )); - // check native asset balance - // proposal amount is in 18 decimal 0.000200000000000000, will be convert to 12 - // decimal 0.000200000000(200000000) because native asset is defined in 12 decimal - assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE + 200000000); - }) - } + // check native asset balance + // proposal amount is in 18 decimal 0.000200000000000000, will be convert to 12 + // decimal 0.000200000000(200000000) because native asset is defined in 12 decimal + assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE + 200000000); + }) + } - #[test] - fn deposit_native_asset_with_percentage_fee() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let amount = 200_000_000_000_000u128; // 200 with 12 decimals + #[test] + fn deposit_native_asset_with_percentage_fee() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let amount = 200_000_000_000_000u128; // 200 with 12 decimals - // test cases - let fee_rate_1 = 500u32; // 5% - let fee_rate_2 = 10000u32; // 100% - let fee_rate_3 = 9999u32; // 99.99% - let fee_rate_4 = 0u32; // 0% - let fee_rate_5 = 15000u32; // 150% + // test cases + let fee_rate_1 = 500u32; // 5% + let fee_rate_2 = 10000u32; // 100% + let fee_rate_3 = 9999u32; // 99.99% + let fee_rate_4 = 0u32; // 0% + let fee_rate_5 = 15000u32; // 150% - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::PercentageFeeHandler, )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // test 5% - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + // test 5% + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -2958,7 +2965,7 @@ pub mod pallet { 0u128, 1_000_000_000_000_000u128 )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -2969,45 +2976,45 @@ pub mod pallet { ) }), )); - // Check balances of Alice after deposit 200 native token - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - // Check reserved native token - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 190_000_000_000_000u128 - ); - // Check fee collected - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 10_000_000_000_000u128); - // Check event - let final_amount_in_deposit_event_1 = 190_000_000_000_000_000_000; // 200 cut 5% then adjust to 18 decimals - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - deposit_nonce: 0, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - final_amount_in_deposit_event_1, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - fee_amount: 10_000_000_000_000u128, - fee_asset_id: NativeLocation::get().into(), - }), - ]); - - // test 100% - // should not work because 100% is out of fee rate - assert_noop!( + // Check balances of Alice after deposit 200 native token + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); + // Check reserved native token + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 190_000_000_000_000u128 + ); + // Check fee collected + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 10_000_000_000_000u128); + // Check event + let final_amount_in_deposit_event_1 = 190_000_000_000_000_000_000; // 200 cut 5% then adjust to 18 decimals + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + deposit_nonce: 0, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + final_amount_in_deposit_event_1, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + fee_amount: 10_000_000_000_000u128, + fee_asset_id: NativeLocation::get().into(), + }), + ]); + + // test 100% + // should not work because 100% is out of fee rate + assert_noop!( SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, @@ -3019,9 +3026,9 @@ pub mod pallet { sygma_percentage_feehandler::Error::::FeeRateOutOfRange ); - // test 99.99% - // override 5% to 99.99% - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + // test 99.99% + // override 5% to 99.99% + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -3029,7 +3036,7 @@ pub mod pallet { 0u128, 1_000_000_000_000_000u128 )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3040,20 +3047,20 @@ pub mod pallet { ) }), )); - // Check reserved native token, should increase by 0.02 to 190.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 190_020_000_000_000u128 - ); - // Check fee collected, should increase by 199.98 to 209.980000000000 - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); - - // test 0% - // override 99.99% to 0% - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + // Check reserved native token, should increase by 0.02 to 190.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 190_020_000_000_000u128 + ); + // Check fee collected, should increase by 199.98 to 209.980000000000 + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); + + // test 0% + // override 99.99% to 0% + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -3061,7 +3068,7 @@ pub mod pallet { 0u128, 1_000_000_000_000_000u128 )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3072,20 +3079,20 @@ pub mod pallet { ) }), )); - // Check reserved native token, should increase by 200 to 390.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 390_020_000_000_000u128 - ); - // Check fee collected, should increase by 0 to 209.980000000000 - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); - - // test 150% - // should not work because 150% is out of fee rate - assert_noop!( + // Check reserved native token, should increase by 200 to 390.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 390_020_000_000_000u128 + ); + // Check fee collected, should increase by 0 to 209.980000000000 + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); + + // test 150% + // should not work because 150% is out of fee rate + assert_noop!( SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, @@ -3097,21 +3104,22 @@ pub mod pallet { sygma_percentage_feehandler::Error::::FeeRateOutOfRange ); - // Check reserved native token, should remain as 390.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 390_020_000_000_000u128 - ); - // Check fee collected, should remain as 209.980000000000 - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); + // Check reserved native token, should remain as 390.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 390_020_000_000_000u128 + ); + // Check fee collected, should remain as 209.980000000000 + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); - // test fee bound: fee rate 5% - let fee_lower_bound = 100_000_000_000_000u128; // 100 - let fee_upper_bound = 1_000_000_000_000_000u128; // 1000 - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + // test fee bound: fee rate 5% + let fee_lower_bound = 100_000_000_000_000u128; // 100 + let fee_upper_bound = 1_000_000_000_000_000u128; + // 1000 + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -3120,9 +3128,9 @@ pub mod pallet { fee_upper_bound )); - // with higher fee lower bound - // 5% fee of 200 token should be 10 but fee lower bound is 100, so fee is 100 now - assert_ok!(SygmaBridge::deposit( + // with higher fee lower bound + // 5% fee of 200 token should be 10 but fee lower bound is 100, so fee is 100 now + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3133,21 +3141,21 @@ pub mod pallet { ) }), )); - // Check reserved native token, should increase by 100 to 490.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 490_020_000_000_000u128 - ); - // Check fee collected, should increase by 100 to 309.980000000000 - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 309_980_000_000_000u128); - - // with lower fee upper bound - // 5% fee of 200000 token should be 10000 but fee upper bound is 1000, so fee is - // 1000 now - assert_ok!(SygmaBridge::deposit( + // Check reserved native token, should increase by 100 to 490.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 490_020_000_000_000u128 + ); + // Check fee collected, should increase by 100 to 309.980000000000 + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 309_980_000_000_000u128); + + // with lower fee upper bound + // 5% fee of 200000 token should be 10000 but fee upper bound is 1000, so fee is + // 1000 now + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new( (Concrete(NativeLocation::get()), Fungible(200_000_000_000_000_000)).into() @@ -3160,46 +3168,46 @@ pub mod pallet { ) }), )); - // Check reserved native token, should increase by 199000 to 199490.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 199_490_020_000_000_000u128 - ); - // Check fee collected, should increase by 1000 to 1309.980000000000 - assert_eq!( - Balances::free_balance(TreasuryAccount::get()), - 1_309_980_000_000_000u128 - ); - }) - } - - #[test] - fn percentage_fee_rate_not_set_for_domain_and_asset() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let amount = 200_000_000_000_000u128; // 200 with 12 decimals - - assert_ok!(SygmaBridge::register_domain( + // Check reserved native token, should increase by 199000 to 199490.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 199_490_020_000_000_000u128 + ); + // Check fee collected, should increase by 1000 to 1309.980000000000 + assert_eq!( + Balances::free_balance(TreasuryAccount::get()), + 1_309_980_000_000_000u128 + ); + }) + } + + #[test] + fn percentage_fee_rate_not_set_for_domain_and_asset() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let amount = 200_000_000_000_000u128; // 200 with 12 decimals + + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // only set fee handler but not set fee rate for domain and asset - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + // only set fee handler but not set fee rate for domain and asset + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::PercentageFeeHandler, )); - // deposit should not go through because fee rate is not set in storage, so when - // get_fee, it returns None - assert_noop!( + // deposit should not go through because fee rate is not set in storage, so when + // get_fee, it returns None + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -3213,38 +3221,38 @@ pub mod pallet { ), bridge::Error::::MissingFeeConfig ); - }) - } + }) + } - #[test] - fn deposit_native_asset_with_percentage_fee_override_basic_fee_handler() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let amount = 200_000_000_000_000u128; // 200 with 12 decimals - let fee = 1_000_000_000_000u128; // 1 with 12 decimals + #[test] + fn deposit_native_asset_with_percentage_fee_override_basic_fee_handler() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let amount = 200_000_000_000_000u128; // 200 with 12 decimals + let fee = 1_000_000_000_000u128; // 1 with 12 decimals - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // set fee handler with basic fee handler and fixed fee - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + // set fee handler with basic fee handler and fixed fee + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3255,25 +3263,25 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount - fee - ); - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); - // Override Basic fee handler to Percentage fee handler with 5% fee rate - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + // Override Basic fee handler to Percentage fee handler with 5% fee rate + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::PercentageFeeHandler, )); - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -3282,7 +3290,7 @@ pub mod pallet { 1_000_000_000_000_000u128 )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3293,161 +3301,161 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount * 2); - // Check reserved native token, should increase by 190 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount - fee + 190_000_000_000_000u128 - ); - // Check fee collected, should increase by 10 - assert_eq!( - Balances::free_balance(TreasuryAccount::get()), - fee + 10_000_000_000_000u128 - ); - }) - } - - #[test] - fn pause_all_bridges_test() { - new_test_ext().execute_with(|| { - let domain_1: DomainID = 1; - let domain_2: DomainID = 2; - let domain_3: DomainID = 3; - - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_1, U256::from(1))); - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_2, U256::from(2))); - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_3, U256::from(3))); - - // all registered domains should be unpaused now - assert!(!IsPaused::::get(domain_1)); - assert!(!IsPaused::::get(domain_2)); - assert!(!IsPaused::::get(domain_3)); - - // permission test: unauthorized account should not be able to pause bridge - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount * 2); + // Check reserved native token, should increase by 190 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + 190_000_000_000_000u128 + ); + // Check fee collected, should increase by 10 + assert_eq!( + Balances::free_balance(TreasuryAccount::get()), + fee + 10_000_000_000_000u128 + ); + }) + } + + #[test] + fn pause_all_bridges_test() { + new_test_ext().execute_with(|| { + let domain_1: DomainID = 1; + let domain_2: DomainID = 2; + let domain_3: DomainID = 3; + + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_1, U256::from(1))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_2, U256::from(2))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_3, U256::from(3))); + + // all registered domains should be unpaused now + assert!(!IsPaused::::get(domain_1)); + assert!(!IsPaused::::get(domain_2)); + assert!(!IsPaused::::get(domain_3)); + + // permission test: unauthorized account should not be able to pause bridge + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::pause_all_bridges(unauthorized_account), bridge::Error::::AccessDenied ); - // Grant ALICE the access - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"pause_all_bridges".to_vec(), ALICE )); - assert_ok!(SygmaBridge::pause_all_bridges(Origin::signed(ALICE))); + assert_ok!(SygmaBridge::pause_all_bridges(Origin::signed(ALICE))); - // all registered domains should be paused now - assert!(IsPaused::::get(domain_1)); - assert!(IsPaused::::get(domain_2)); - assert!(IsPaused::::get(domain_3)); + // all registered domains should be paused now + assert!(IsPaused::::get(domain_1)); + assert!(IsPaused::::get(domain_2)); + assert!(IsPaused::::get(domain_3)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::AllBridgePaused { - sender: ALICE, - })]); - }) - } + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::AllBridgePaused { + sender: ALICE, + })]); + }) + } - #[test] - fn unpause_all_bridges_test() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + #[test] + fn unpause_all_bridges_test() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let domain_1: DomainID = 1; - let domain_2: DomainID = 2; - let domain_3: DomainID = 3; + let domain_1: DomainID = 1; + let domain_2: DomainID = 2; + let domain_3: DomainID = 3; - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_1, U256::from(1))); - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_2, U256::from(2))); - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_3, U256::from(3))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_1, U256::from(1))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_2, U256::from(2))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_3, U256::from(3))); - // mpc address not setup, should be error - assert_noop!( + // mpc address not setup, should be error + assert_noop!( SygmaBridge::unpause_all_bridges(Origin::root()), bridge::Error::::MissingMpcAddress ); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // permission test: unauthorized account should not be able to pause bridge - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // permission test: unauthorized account should not be able to pause bridge + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::unpause_all_bridges(unauthorized_account), bridge::Error::::AccessDenied ); - // Grant ALICE the access - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unpause_all_bridges".to_vec(), ALICE )); - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_1)); - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_2)); - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_3)); - - // all registered domains should be paused now - assert!(IsPaused::::get(domain_1)); - assert!(IsPaused::::get(domain_2)); - assert!(IsPaused::::get(domain_3)); - - assert_ok!(SygmaBridge::unpause_all_bridges(Origin::signed(ALICE))); - - // all registered domains should be unpaused now - assert!(!IsPaused::::get(domain_1)); - assert!(!IsPaused::::get(domain_2)); - assert!(!IsPaused::::get(domain_3)); - - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::AllBridgeUnpaused { sender: ALICE }, - )]); - }) - } - - #[test] - fn deposit_nonce_fix_should_work() { - new_test_ext().execute_with(|| { - // Nonce from source chain start from 1, set first batch of nonce under [1, 63] - for nonce in 1..64u64 { - SygmaBridge::set_proposal_executed(nonce, 0); - } - // Nonce 0 should not be set - assert!(!SygmaBridge::is_proposal_executed(0, 0)); - // Nonce 1 should be set - assert!(SygmaBridge::is_proposal_executed(1, 0)); - // Nonce 63 should be set - assert!(SygmaBridge::is_proposal_executed(63, 0)); - - // set second batch of nonce under [64, 127] - for nonce in 64..128u64 { - SygmaBridge::set_proposal_executed(nonce, 0); - } - // Nonce 64 should be set - assert!(SygmaBridge::is_proposal_executed(64, 0)); - // Nonce 127 should be set - assert!(SygmaBridge::is_proposal_executed(127, 0)); - // Nonce 128 should not be set - assert!(!SygmaBridge::is_proposal_executed(128, 0)); - - // set future batch of nonce under [256, 300] - for nonce in 256..301u64 { - SygmaBridge::set_proposal_executed(nonce, 0); - } - // Nonce 256 should be set - assert!(SygmaBridge::is_proposal_executed(256, 0)); - // Nonce 300 should be set - assert!(SygmaBridge::is_proposal_executed(300, 0)); - // Nonce 301 should not be set - assert!(!SygmaBridge::is_proposal_executed(301, 0)); - }) - } - } + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_1)); + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_2)); + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_3)); + + // all registered domains should be paused now + assert!(IsPaused::::get(domain_1)); + assert!(IsPaused::::get(domain_2)); + assert!(IsPaused::::get(domain_3)); + + assert_ok!(SygmaBridge::unpause_all_bridges(Origin::signed(ALICE))); + + // all registered domains should be unpaused now + assert!(!IsPaused::::get(domain_1)); + assert!(!IsPaused::::get(domain_2)); + assert!(!IsPaused::::get(domain_3)); + + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::AllBridgeUnpaused { sender: ALICE }, + )]); + }) + } + + #[test] + fn deposit_nonce_fix_should_work() { + new_test_ext().execute_with(|| { + // Nonce from source chain start from 1, set first batch of nonce under [1, 63] + for nonce in 1..64u64 { + SygmaBridge::set_proposal_executed(nonce, 0); + } + // Nonce 0 should not be set + assert!(!SygmaBridge::is_proposal_executed(0, 0)); + // Nonce 1 should be set + assert!(SygmaBridge::is_proposal_executed(1, 0)); + // Nonce 63 should be set + assert!(SygmaBridge::is_proposal_executed(63, 0)); + + // set second batch of nonce under [64, 127] + for nonce in 64..128u64 { + SygmaBridge::set_proposal_executed(nonce, 0); + } + // Nonce 64 should be set + assert!(SygmaBridge::is_proposal_executed(64, 0)); + // Nonce 127 should be set + assert!(SygmaBridge::is_proposal_executed(127, 0)); + // Nonce 128 should not be set + assert!(!SygmaBridge::is_proposal_executed(128, 0)); + + // set future batch of nonce under [256, 300] + for nonce in 256..301u64 { + SygmaBridge::set_proposal_executed(nonce, 0); + } + // Nonce 256 should be set + assert!(SygmaBridge::is_proposal_executed(256, 0)); + // Nonce 300 should be set + assert!(SygmaBridge::is_proposal_executed(300, 0)); + // Nonce 301 should not be set + assert!(!SygmaBridge::is_proposal_executed(301, 0)); + }) + } + } } diff --git a/xcm-bridge/Cargo.toml b/xcm-bridge/Cargo.toml index 7d52b2be..b741af66 100644 --- a/xcm-bridge/Cargo.toml +++ b/xcm-bridge/Cargo.toml @@ -14,6 +14,8 @@ frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } # Polkadot xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 1e8849bd..a0af6758 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -1,20 +1,23 @@ #![cfg_attr(not(feature = "std"), no_std)] -mod mock; - pub use self::pallet::*; +mod mock; + #[frame_support::pallet] pub mod pallet { - use sygma_traits::{Bridge, AssetReserveLocationParser, AssetTypeIdentifier}; use frame_support::{ dispatch::DispatchResult, pallet_prelude::*, - traits::{ContainsPair, StorageVersion}, + traits::StorageVersion, }; - use xcm::latest::{prelude::*, MultiLocation, Weight as XCMWeight}; + use sp_runtime::traits::Zero; + use sp_std::{prelude::*, vec}; + use xcm::latest::{MultiLocation, prelude::*, Weight as XCMWeight}; use xcm_executor::traits::WeightBounds; + use sygma_traits::{AssetReserveLocationParser, Bridge}; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); #[pallet::pallet] @@ -36,7 +39,7 @@ pub mod pallet { type SelfLocation: Get; } - enum TransferKind { + pub enum TransferKind { /// Transfer self reserve asset. SelfReserveAsset, /// To reserve location. @@ -56,55 +59,62 @@ pub mod pallet { FailToWeightMessage, XcmExecutionFailed, InvalidDestination, + UnknownTransferType, + CannotReanchor, } - struct Xcm { + #[derive(PartialEq, Eq, Clone, Encode, Decode)] + struct XcmObject { asset: MultiAsset, fee: MultiAsset, origin: MultiLocation, dest: MultiLocation, recipient: MultiLocation, weight: XCMWeight, + _unused: PhantomData, } - pub trait XcmHandler { - fn transfer_kind(&self) -> Result; + pub trait XcmHandler { + fn transfer_kind(&self) -> Option; fn create_instructions(&self) -> Result, DispatchError>; - fn execute_instructions(&self, xcm_message: Xcm) -> DispatchResult; + fn execute_instructions(&self, xcm_instructions: &mut Xcm) -> DispatchResult; } - impl XcmHandler for Xcm { + impl XcmHandler for XcmObject { /// Get the transfer kind. - fn transfer_kind(&self) -> Result { - let asset_location = Pallet::::reserved_location(&self.asset).ok_or()?; - if asset_location == T::SelfLocation { - TransferKind::SelfReserveAsset + fn transfer_kind(&self) -> Option { + let asset_location = Pallet::::reserved_location(&self.asset.clone())?; + if asset_location == T::SelfLocation::get() { + Some(TransferKind::SelfReserveAsset) } else if asset_location == self.dest { - TransferKind::ToReserve + Some(TransferKind::ToReserve) } else { - TransferKind::ToNonReserve + Some(TransferKind::ToNonReserve) } } fn create_instructions(&self) -> Result, DispatchError> { - let kind = Self::transfer_kind(self)?; - - let mut xcm_instructions = match kind { - SelfReserveAsset => Self::transfer_self_reserve_asset(self.assets, self.fee, self.dest, self.recipient, self.weight)?, - ToReserve => Self::transfer_to_reserve_asset(self.assets, self.fee, self.dest, self.recipient, self.weight)?, - ToNonReserve => Self::transfer_to_non_reserve_asset( - self.assets, - self.fee, + let kind = Self::transfer_kind(self).ok_or(Error::::UnknownTransferType)?; + + let mut assets = MultiAssets::new(); + assets.push(self.asset.clone()); + + let xcm_instructions = match kind { + TransferKind::SelfReserveAsset => Pallet::::transfer_self_reserve_asset(assets, self.fee.clone(), self.dest, self.recipient, WeightLimit::Limited(self.weight))?, + TransferKind::ToReserve => Pallet::::transfer_to_reserve_asset(assets, self.fee.clone(), self.dest, self.recipient, WeightLimit::Limited(self.weight))?, + TransferKind::ToNonReserve => Pallet::::transfer_to_non_reserve_asset( + assets, + self.fee.clone(), self.dest, self.dest.clone(), self.recipient, - self.weight, + WeightLimit::Limited(self.weight), )?, }; Ok(xcm_instructions) } - fn execute_instructions(&self, xcm_instructions: Xcm) -> DispatchResult { + fn execute_instructions(&self, xcm_instructions: &mut Xcm) -> DispatchResult { let message_weight = T::Weigher::weight(xcm_instructions).map_err(|()| Error::::FailToWeightMessage)?; let hash = xcm_instructions.using_encoded(sp_io::hashing::blake2_256); @@ -117,7 +127,7 @@ pub mod pallet { message_weight, ).ensure_complete().map_err(|_| Error::::XcmExecutionFailed)?; - oK(()) + Ok(()) } } @@ -143,17 +153,18 @@ pub mod pallet { let (dest_location, recipient) = Pallet::::extract_dest(&dest).ok_or(Error::::InvalidDestination)?; - let xcm = Xcm:: { + let xcm = XcmObject:: { asset: asset.clone(), fee: asset.clone(), // TODO: fee is asset? origin: origin_location.clone(), - dest_location, + dest: dest_location, recipient, weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), + _unused: PhantomData, }; let mut msg = xcm.create_instructions()?; - xcm.execute_instructions(msg)?; + xcm.execute_instructions(&mut msg)?; Ok(()) } @@ -239,12 +250,12 @@ pub mod pallet { assets: All.into(), reserve, xcm: Xcm(vec![ - Self::buy_execution(half(&fee), &reserve, dest_weight_limit.clone())?, + Self::buy_execution(Self::half(&fee), &reserve, dest_weight_limit.clone())?, DepositReserveAsset { assets: AllCounted(max_assets).into(), dest: reanchored_dest, xcm: Xcm(vec![ - Self::buy_execution(half(&fee), &dest, dest_weight_limit)?, + Self::buy_execution(Self::half(&fee), &dest, dest_weight_limit)?, Self::deposit_asset(recipient, max_assets), ]), }, @@ -252,5 +263,44 @@ pub mod pallet { }, ])) } + + fn deposit_asset(recipient: MultiLocation, max_assets: u32) -> Instruction<()> { + DepositAsset { + assets: AllCounted(max_assets).into(), + beneficiary: recipient, + } + } + + fn buy_execution( + asset: MultiAsset, + at: &MultiLocation, + weight_limit: WeightLimit, + ) -> Result, DispatchError> { + let ancestry = T::SelfLocation::get(); + + let fees = asset.reanchored(at, ancestry.interior).map_err(|_| Error::::CannotReanchor)?; + + Ok(BuyExecution { fees, weight_limit }) + } + + /// Returns amount if `asset` is fungible, or zero. + fn fungible_amount(asset: &MultiAsset) -> u128 { + if let Fungible(amount) = &asset.fun { + *amount + } else { + Zero::zero() + } + } + + fn half(asset: &MultiAsset) -> MultiAsset { + let half_amount = Self::fungible_amount(asset) + .checked_div(2) + .expect("div 2 can't overflow; qed"); + MultiAsset { + fun: Fungible(half_amount), + id: asset.id, + } + } } } + From 9fb92c92b93b8fea0344c187ffe4768c9eabd60b Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Thu, 4 Jan 2024 11:47:25 -0500 Subject: [PATCH 16/30] impl the missing logic for events and sygma multilocation pattern --- Cargo.lock | 5 ++ bridge-forwarder/Cargo.toml | 5 ++ bridge-forwarder/src/lib.rs | 48 ++++++++++++++--- bridge/Cargo.toml | 3 ++ bridge/src/lib.rs | 5 +- bridge/src/xcm_asset_transactor.rs | 84 ++++++++++++++++-------------- traits/src/lib.rs | 5 +- xcm-bridge/src/lib.rs | 22 ++++++-- 8 files changed, 122 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4a756821..ed007d68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9595,7 +9595,9 @@ dependencies = [ "arrayref", "assert_matches", "bounded-collections", + "cumulus-pallet-xcm", "cumulus-primitives-core", + "cumulus-primitives-utility", "ethabi", "fixed", "frame-benchmarking", @@ -9634,6 +9636,9 @@ dependencies = [ name = "sygma-bridge-forwarder" version = "0.3.0" dependencies = [ + "cumulus-pallet-xcm", + "cumulus-primitives-core", + "cumulus-primitives-utility", "frame-support", "frame-system", "pallet-assets", diff --git a/bridge-forwarder/Cargo.toml b/bridge-forwarder/Cargo.toml index aec5c2b5..1dfb8ebc 100644 --- a/bridge-forwarder/Cargo.toml +++ b/bridge-forwarder/Cargo.toml @@ -18,6 +18,11 @@ xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-s xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +# Cumulus +cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } + # Local sygma-traits = { path = "../traits", default-features = false } diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index 423b956b..8b57c693 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -9,7 +9,7 @@ pub use self::pallet::*; pub mod pallet { use frame_support::pallet_prelude::*; use frame_support::traits::StorageVersion; - use xcm::latest::{MultiAsset, MultiLocation}; + use xcm::latest::{MultiAsset, MultiLocation, Junction}; use sygma_traits::{Bridge, TransactorForwarder}; @@ -29,17 +29,51 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub (super) fn deposit_event)] pub enum Event { - XCMTransferForward {}, - OtherWorldTransferForward {}, + XCMTransferForward { + asset: MultiAsset, + origin: MultiLocation, + dest: MultiLocation, + }, + OtherWorldTransferForward { + asset: MultiAsset, + origin: MultiLocation, + dest: MultiLocation, + }, } impl TransactorForwarder for Pallet { - fn xcm_transactor_forwarder(origin: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult { - T::XCMBridge::transfer(origin, what, who) + fn xcm_transactor_forwarder(origin: [u8; 32], what: MultiAsset, dest: MultiLocation) -> DispatchResult { + T::XCMBridge::transfer(origin, what.clone(), dest.clone())?; + + let origin_location: MultiLocation = Junction::AccountId32 { + network: None, + id: origin, + }.into(); + + Pallet::::deposit_event(Event::XCMTransferForward { + asset: what, + origin: origin_location, + dest, + }); + + Ok(()) } - fn other_world_transactor_forwarder(origin: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult { - T::SygmaBridge::transfer(origin, what, who) + fn other_world_transactor_forwarder(origin: [u8; 32], what: MultiAsset, dest: MultiLocation) -> DispatchResult { + T::SygmaBridge::transfer(origin, what.clone(), dest.clone())?; + + let origin_location: MultiLocation = Junction::AccountId32 { + network: None, + id: origin, + }.into(); + + Pallet::::deposit_event(Event::OtherWorldTransferForward { + asset: what, + origin: origin_location, + dest, + }); + + Ok(()) } } } diff --git a/bridge/Cargo.toml b/bridge/Cargo.toml index f5658dba..d4c53368 100644 --- a/bridge/Cargo.toml +++ b/bridge/Cargo.toml @@ -36,7 +36,10 @@ xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/par # Cumulus cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +# Local sygma-traits = { path = "../traits", default-features = false } sygma-access-segregator = { path = "../access-segregator", default-features = false } sygma-basic-feehandler = { path = "../basic-fee-handler", default-features = false } diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index bd490458..099da98a 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -684,7 +684,11 @@ pub mod pallet { } impl> AssetTypeIdentifier for Pallet { + /// check if the given MultiAsset is a native asset fn is_native_asset(asset: &MultiAsset) -> bool { + // currently there are two multilocations are considered as native asset: + // 1. integrated parachain native asset(MultiLocation::here()) + // 2. other parachain native asset(MultiLocation::new(1, X1(Parachain(T::get().into())))) let native_locations = [ MultiLocation::here(), MultiLocation::new(1, X1(Parachain(T::get().into()))), @@ -699,7 +703,6 @@ pub mod pallet { } } - impl Bridge for Pallet where ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, { diff --git a/bridge/src/xcm_asset_transactor.rs b/bridge/src/xcm_asset_transactor.rs index 18f81baa..aae6b711 100644 --- a/bridge/src/xcm_asset_transactor.rs +++ b/bridge/src/xcm_asset_transactor.rs @@ -1,77 +1,81 @@ use core::marker::PhantomData; + use codec::Encode; use xcm::latest::{Junction, MultiAsset, MultiLocation, XcmContext}; -use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; use xcm::prelude::*; use xcm_executor::{Assets, traits::TransactAsset}; +use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; + +use crate::mock::slice_to_generalkey; + pub struct XCMAssetTransactor(PhantomData<(CurrencyTransactor, FungiblesTransactor, AssetTypeChecker, Forwarder)>); impl TransactAsset for XCMAssetTransactor { // deposit_asset implements the TransactAsset deposit_asset method and contains the logic to classify // the asset recipient location: // 1. recipient is on the local parachain - // 2. recipient is on the remote parachain - // 3, recipient is on non-substrate chain(evm, cosmos, etc.) + // 2. recipient is on non-substrate chain(evm, cosmos, etc.) + // 3. recipient is on the remote parachain fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { match (who.parents, who.first_interior()) { - // 1. recipient is the local parachain + // 1. recipient is on the local parachain (0, Some(Parachain(_))) => { - // check if the asset is native or foreign, and call the corresponding deposit_asset() + // check if the asset is native, and call the corresponding deposit_asset() if AssetTypeChecker::is_native_asset(what) { CurrencyTransactor::deposit_asset(what, who, context)?; } else { FungiblesTransactor::deposit_asset(what, who, context)? } } - // recipient is remote chain - // trying to eliminate the forward logic here by adding the XCM handler pallet as one of the generic type for XCMAssetTransactor + // recipient is on the remote chain (1, Some(Parachain(_))) => { // 2. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet - // TODO: this is the sygma multilocation pattern - // TODO: the junctions below is just an temporary example, will change it to proper sygma bridge standard, see the link below: - // (https://www.notion.so/chainsafe/Sygma-as-an-Independent-pallet-c481f00ccff84ff49ce917c8b2feacda?pvs=4#6e51e6632e254b9b9a01444ef7297969) - if who.interior == X3(Parachain(1000), GeneralKey{length: 8, data: [1u8; 32]}, GeneralKey {length:8, data: [2u8; 32]}) { - // check if the asset is native or foreign, and deposit the asset to a tmp account first - let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey {length: 8, data: [2u8; 32]})).encode()); - if AssetTypeChecker::is_native_asset(what) { - CurrencyTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; - } else { - FungiblesTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? - } + match who.interior { + (X5(Parachain(1000), slice_to_generalkey(b"sygma"), slice_to_generalkey(b"sygma-bridge"), GeneralIndex(..), GeneralKey { .. })) => { + // check if the asset is native or foreign, and deposit the asset to a tmp account first + let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey { length: 8, data: [2u8; 32] })).encode()); + if AssetTypeChecker::is_native_asset(what) { + CurrencyTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; + } else { + FungiblesTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? + } - // TODO: call deposit() extrisic in sygmaBrdige pallet. Sygma bridge pallet should also be in the PhantomData type - Forwarder::other_world_transactor_forwarder(tmp_account, what.clone(), *who).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; - - return Ok(()) - } + Forwarder::other_world_transactor_forwarder(tmp_account, what.clone(), who.into()).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + } + _ => { + // 3. recipient is on remote parachain + // xcm message must have a sender(origin), so a tmp account derived from pallet would be necessary here + let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey { length: 8, data: [2u8; 32] })).encode()); - // 3. recipient is remote parachain - // recipient is remote parachain - // xcm message must have a sender(origin), so a tmp account derived from pallet would be used - let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey {length: 8, data: [2u8; 32]})).encode()); + // check if the asset is native or foreign, and call the corresponding deposit_asset(), recipient will be the derived tmp account + // xcm message execution + if AssetTypeChecker::is_native_asset(what) { + CurrencyTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; + } else { + FungiblesTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? + } - // check if the asset is native or foreign, and call the corresponding deposit_asset(), recipient will be the derived tmp account - // xcm message execution - if AssetTypeChecker::is_native_asset(what) { - CurrencyTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; - } else { - FungiblesTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)? + Forwarder::xcm_transactor_forwarder(tmp_account, what.clone(), who.into()).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + } } - - // TODO: call the xcm handler pallet to construct the xcm message and execute it(to other remote parachain route) - Forwarder::xcm_transactor_forwarder(tmp_account, what.clone(), *who).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; } - // Other destination multilocation not supported, return Err + // Other destination multiLocation not supported, return Err _ => { return Err(XcmError::DestinationUnsupported); } } + Ok(()) } - fn withdraw_asset(_what: &MultiAsset, _who: &MultiLocation, _maybe_context: Option<&XcmContext>) -> Result { - // TODO: - Ok(Assets::new()) + fn withdraw_asset(what: &MultiAsset, who: &MultiLocation, maybe_context: Option<&XcmContext>) -> Result { + let assets = if AssetTypeChecker::is_native_asset(what) { + CurrencyTransactor::withdraw_asset(what, who, maybe_context)? + } else { + FungiblesTransactor::withdraw_asset(what, who, maybe_context)? + }; + + Ok(assets) } } diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 2000539a..03a2f81d 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -63,15 +63,14 @@ pub trait DecimalConverter { fn convert_from(asset: &MultiAsset) -> Option; } -// TODO: implement this method for local mock and standalone use // when integrating with parachain, parachain team can implement their own version pub trait AssetTypeIdentifier { fn is_native_asset(asset: &MultiAsset) -> bool; } pub trait TransactorForwarder { - fn xcm_transactor_forwarder(sender: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult; - fn other_world_transactor_forwarder(sender: [u8; 32], what: MultiAsset, who: MultiLocation) -> DispatchResult; + fn xcm_transactor_forwarder(sender: [u8; 32], what: MultiAsset, dest: MultiLocation) -> DispatchResult; + fn other_world_transactor_forwarder(sender: [u8; 32], what: MultiAsset, dest: MultiLocation) -> DispatchResult; } pub trait Bridge { diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index a0af6758..ef0288ad 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -1,3 +1,6 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + #![cfg_attr(not(feature = "std"), no_std)] pub use self::pallet::*; @@ -28,7 +31,6 @@ pub mod pallet { pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - /// Current pallet index defined in runtime type PalletIndex: Get; type Weigher: WeightBounds; @@ -51,7 +53,11 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub (super) fn deposit_event)] pub enum Event { - XCMTransferSend {}, + XCMTransferSend { + asset: MultiAsset, + origin: MultiLocation, + dest: MultiLocation, + }, } #[pallet::error] @@ -81,7 +87,6 @@ pub mod pallet { } impl XcmHandler for XcmObject { - /// Get the transfer kind. fn transfer_kind(&self) -> Option { let asset_location = Pallet::::reserved_location(&self.asset.clone())?; if asset_location == T::SelfLocation::get() { @@ -162,15 +167,22 @@ pub mod pallet { weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), _unused: PhantomData, }; - let mut msg = xcm.create_instructions()?; + let mut msg = xcm.create_instructions()?; xcm.execute_instructions(&mut msg)?; + Pallet::::deposit_event(Event::XCMTransferSend { + asset, + origin: origin_location, + dest, + }); + Ok(()) } } impl Pallet { + /// extract the dest_location, recipient_location pub fn extract_dest(dest: &MultiLocation) -> Option<(MultiLocation, MultiLocation)> { match (dest.parents, dest.first_interior()) { // parents must be 1 here because only parents as 1 can be forwarded to xcm bridge logic @@ -179,10 +191,12 @@ pub mod pallet { MultiLocation::new(1, X1(Parachain(*id))), MultiLocation::new(0, dest.interior().clone().split_first().0), )), + // parent: relay chain (1, _) => Some(( MultiLocation::parent(), MultiLocation::new(0, dest.interior().clone()), )), + // local and children parachain have been filterred out in the TransactAsset _ => None, } } From be06effe03af12bbc7deec2bd692e642e2a7b1a6 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Fri, 5 Jan 2024 13:02:13 -0500 Subject: [PATCH 17/30] fix the substrate dependency compile issue --- bridge-forwarder/Cargo.toml | 3 +++ bridge/Cargo.toml | 5 +++++ bridge/src/xcm_asset_transactor.rs | 12 ++++++------ xcm-bridge/Cargo.toml | 7 +++++++ xcm-bridge/src/lib.rs | 1 + 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/bridge-forwarder/Cargo.toml b/bridge-forwarder/Cargo.toml index 1dfb8ebc..9625e767 100644 --- a/bridge-forwarder/Cargo.toml +++ b/bridge-forwarder/Cargo.toml @@ -48,6 +48,9 @@ std = [ "xcm/std", "xcm-builder/std", "xcm-executor/std", + "cumulus-primitives-core/std", + "cumulus-primitives-utility/std", + "cumulus-pallet-xcm/std", "sygma-traits/std", ] runtime-benchmarks = [ diff --git a/bridge/Cargo.toml b/bridge/Cargo.toml index d4c53368..28d1319c 100644 --- a/bridge/Cargo.toml +++ b/bridge/Cargo.toml @@ -96,6 +96,9 @@ std = [ "frame-support/std", "frame-system/std", "frame-benchmarking/std", + "cumulus-primitives-core/std", + "cumulus-primitives-utility/std", + "cumulus-pallet-xcm/std", "xcm/std", "xcm-builder/std", "xcm-executor/std", @@ -106,5 +109,7 @@ std = [ "sygma-basic-feehandler/std", "sygma-percentage-feehandler/std", "sygma-fee-handler-router/std", + "sygma-bridge-forwarder/std", + "sygma-xcm-bridge/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/bridge/src/xcm_asset_transactor.rs b/bridge/src/xcm_asset_transactor.rs index aae6b711..36964e7f 100644 --- a/bridge/src/xcm_asset_transactor.rs +++ b/bridge/src/xcm_asset_transactor.rs @@ -4,11 +4,9 @@ use codec::Encode; use xcm::latest::{Junction, MultiAsset, MultiLocation, XcmContext}; use xcm::prelude::*; use xcm_executor::{Assets, traits::TransactAsset}; - +use hex_literal::hex; use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; -use crate::mock::slice_to_generalkey; - pub struct XCMAssetTransactor(PhantomData<(CurrencyTransactor, FungiblesTransactor, AssetTypeChecker, Forwarder)>); impl TransactAsset for XCMAssetTransactor { @@ -32,7 +30,9 @@ impl { // 2. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet match who.interior { - (X5(Parachain(1000), slice_to_generalkey(b"sygma"), slice_to_generalkey(b"sygma-bridge"), GeneralIndex(..), GeneralKey { .. })) => { + // sygma: 7379676d61000000000000000000000000000000000000000000000000000000 + // sygma-bridge: 7379676d612d6272696467650000000000000000000000000000000000000000 + X5(Parachain(1000), GeneralKey { length: 5, data: hex!["7379676d61000000000000000000000000000000000000000000000000000000"]}, GeneralKey { length: 12, data: hex!["7379676d612d6272696467650000000000000000000000000000000000000000"]}, GeneralIndex(..), GeneralKey { .. }) => { // check if the asset is native or foreign, and deposit the asset to a tmp account first let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey { length: 8, data: [2u8; 32] })).encode()); if AssetTypeChecker::is_native_asset(what) { @@ -41,7 +41,7 @@ impl { // 3. recipient is on remote parachain @@ -56,7 +56,7 @@ impl Result, DispatchError> { let kind = Self::transfer_kind(self).ok_or(Error::::UnknownTransferType)?; From 8841e9abbea4685489bed059e394d137246c5328 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Tue, 9 Jan 2024 14:36:28 -0500 Subject: [PATCH 18/30] add relay chain setup --- Cargo.lock | 911 ++++++++++++++++++++++++++++------- xcm-bridge/Cargo.toml | 29 +- xcm-bridge/src/mock.rs | 2 + xcm-bridge/src/mock/relay.rs | 239 +++++++++ 4 files changed, 1000 insertions(+), 181 deletions(-) create mode 100644 xcm-bridge/src/mock/relay.rs diff --git a/Cargo.lock b/Cargo.lock index ed007d68..06b0fa3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -920,6 +920,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bounded-vec" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68534a48cbf63a4b1323c433cf21238c9ec23711e0df13b08c33e5c2082663ce" +dependencies = [ + "thiserror", +] + [[package]] name = "bs58" version = "0.4.0" @@ -1215,6 +1224,18 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +[[package]] +name = "coarsetime" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71367d3385c716342014ad17e3d19f7788ae514885a1f4c24f500260fb365e1a" +dependencies = [ + "libc", + "once_cell", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1512,14 +1533,20 @@ dependencies = [ ] [[package]] -name = "crossbeam-utils" -version = "0.8.16" +name = "crossbeam-queue" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if", + "crossbeam-utils", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "crunchy" version = "0.2.2" @@ -1599,6 +1626,64 @@ dependencies = [ "cipher 0.4.4", ] +[[package]] +name = "cumulus-pallet-dmp-queue" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", +] + +[[package]] +name = "cumulus-pallet-parachain-system" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "bytes", + "cumulus-pallet-parachain-system-proc-macro", + "cumulus-primitives-core", + "cumulus-primitives-parachain-inherent", + "environmental", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "polkadot-parachain-primitives", + "scale-info", + "sp-core", + "sp-externalities", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", + "sp-version", + "staging-xcm", + "trie-db", +] + +[[package]] +name = "cumulus-pallet-parachain-system-proc-macro" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "cumulus-pallet-xcm" version = "0.1.0" @@ -1615,10 +1700,31 @@ dependencies = [ "staging-xcm", ] +[[package]] +name = "cumulus-pallet-xcmp-queue" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "cumulus-primitives-core", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "polkadot-runtime-common", + "rand_chacha 0.3.1", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + [[package]] name = "cumulus-primitives-core" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "polkadot-core-primitives", @@ -1632,10 +1738,33 @@ dependencies = [ "staging-xcm", ] +[[package]] +name = "cumulus-primitives-parachain-inherent" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "cumulus-test-relay-sproof-builder", + "parity-scale-codec", + "sc-client-api", + "scale-info", + "sp-api", + "sp-core", + "sp-inherents", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-storage", + "sp-trie", + "tracing", +] + [[package]] name = "cumulus-primitives-utility" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -1650,6 +1779,38 @@ dependencies = [ "staging-xcm-executor", ] +[[package]] +name = "cumulus-relay-chain-interface" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "futures", + "jsonrpsee-core", + "parity-scale-codec", + "polkadot-overseer", + "sc-client-api", + "sp-api", + "sp-blockchain", + "sp-state-machine", + "thiserror", +] + +[[package]] +name = "cumulus-test-relay-sproof-builder" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "cumulus-primitives-core", + "parity-scale-codec", + "polkadot-primitives", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", +] + [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -2331,6 +2492,30 @@ dependencies = [ "futures", ] +[[package]] +name = "expander" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a718c0675c555c5f976fff4ea9e2c150fa06cefa201cadef87cfbf9324075881" +dependencies = [ + "blake3", + "fs-err", + "proc-macro2", + "quote", +] + +[[package]] +name = "expander" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3774182a5df13c3d1690311ad32fbe913feef26baba609fa2dd5f72042bd2ab6" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2", + "quote", +] + [[package]] name = "expander" version = "2.0.0" @@ -2371,6 +2556,31 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "fatality" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad875162843b0d046276327afe0136e9ed3a23d5a754210fb6f1f33610d39ab" +dependencies = [ + "fatality-proc-macro", + "thiserror", +] + +[[package]] +name = "fatality-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5aa1e3ae159e592ad222dc90c5acbad632b527779ba88486abe92782ab268bd" +dependencies = [ + "expander 0.0.4", + "indexmap 1.9.3", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", + "thiserror", +] + [[package]] name = "fdlimit" version = "0.2.1" @@ -2403,7 +2613,7 @@ dependencies = [ [[package]] name = "fflonk" version = "0.1.0" -source = "git+https://github.com/w3f/fflonk#e141d4b6f42fb481aefe1b479788694945b6940d" +source = "git+https://github.com/w3f/fflonk#1e854f35e9a65d08b11a86291405cdc95baa0a35" dependencies = [ "ark-ec", "ark-ff", @@ -2516,7 +2726,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", ] @@ -2539,7 +2749,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "frame-support-procedural", @@ -2564,7 +2774,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "Inflector", "array-bytes", @@ -2612,7 +2822,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2623,7 +2833,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -2640,7 +2850,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "frame-system", @@ -2670,7 +2880,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-recursion", "futures", @@ -2692,7 +2902,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "aquamarine", "bitflags 1.3.2", @@ -2732,12 +2942,12 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "Inflector", "cfg-expr", "derive-syn-parse", - "expander", + "expander 2.0.0", "frame-support-procedural-tools", "itertools", "macro_magic", @@ -2750,7 +2960,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2762,7 +2972,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "proc-macro2", "quote", @@ -2772,7 +2982,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "cfg-if", "frame-support", @@ -2791,7 +3001,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -2806,7 +3016,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "sp-api", @@ -2815,7 +3025,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "parity-scale-codec", @@ -3569,6 +3779,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "integer-encoding" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" + [[package]] name = "integer-sqrt" version = "0.1.5" @@ -3845,7 +4061,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "polkadot-primitives", @@ -4720,6 +4936,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "mick-jaeger" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69672161530e8aeca1d1400fbf3f1a1747ff60ea604265a4e906c2442df20532" +dependencies = [ + "futures", + "rand 0.8.5", + "thrift", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -4822,9 +5049,9 @@ dependencies = [ [[package]] name = "multihash-derive" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" +checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -4890,6 +5117,12 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" + [[package]] name = "netlink-packet-core" version = "0.4.2" @@ -5233,6 +5466,47 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "orchestra" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "227585216d05ba65c7ab0a0450a3cf2cbd81a98862a54c4df8e14d5ac6adb015" +dependencies = [ + "async-trait", + "dyn-clonable", + "futures", + "futures-timer", + "orchestra-proc-macro", + "pin-project", + "prioritized-metered-channel", + "thiserror", + "tracing", +] + +[[package]] +name = "orchestra-proc-macro" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2871aadd82a2c216ee68a69837a526dfe788ecbe74c4c5038a6acdbff6653066" +dependencies = [ + "expander 0.0.6", + "itertools", + "petgraph", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ordered-float" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" +dependencies = [ + "num-traits", +] + [[package]] name = "p256" version = "0.11.1" @@ -5258,7 +5532,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5276,7 +5550,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5292,7 +5566,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "frame-system", @@ -5309,7 +5583,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "frame-system", @@ -5325,7 +5599,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "frame-system", @@ -5339,7 +5613,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5363,7 +5637,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5378,7 +5652,7 @@ dependencies = [ [[package]] name = "pallet-collator-selection" version = "3.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5397,7 +5671,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5420,7 +5694,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5434,7 +5708,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "docify", "frame-benchmarking", @@ -5453,7 +5727,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5476,7 +5750,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "frame-system", @@ -5490,7 +5764,7 @@ dependencies = [ [[package]] name = "pallet-message-queue" version = "7.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5521,7 +5795,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "frame-system", @@ -5543,7 +5817,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -5565,7 +5839,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "log", "sp-arithmetic", @@ -5574,7 +5848,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5589,7 +5863,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5608,7 +5882,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "frame-system", @@ -5624,7 +5898,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -5640,7 +5914,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -5652,7 +5926,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5669,7 +5943,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-benchmarking", "frame-support", @@ -5681,10 +5955,31 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-xcm" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "bounded-collections", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-executor", +] + [[package]] name = "parachains-common" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "cumulus-primitives-core", "cumulus-primitives-utility", @@ -6004,33 +6299,163 @@ dependencies = [ ] [[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "platforms" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "platforms" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ab3f592e6fb464fc9712d8d6e6912de6473954635fd76a589d832cffcbb0" + +[[package]] +name = "polkadot-core-primitives" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "polkadot-node-jaeger" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "lazy_static", + "log", + "mick-jaeger", + "parity-scale-codec", + "parking_lot 0.12.1", + "polkadot-node-primitives", + "polkadot-primitives", + "sc-network", + "sp-core", + "thiserror", + "tokio", +] + +[[package]] +name = "polkadot-node-metrics" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "bs58 0.5.0", + "futures", + "futures-timer", + "log", + "parity-scale-codec", + "polkadot-primitives", + "prioritized-metered-channel", + "sc-cli", + "sc-service", + "sc-tracing", + "substrate-prometheus-endpoint", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-network-protocol" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "async-channel", + "async-trait", + "bitvec", + "derive_more", + "fatality", + "futures", + "hex", + "parity-scale-codec", + "polkadot-node-jaeger", + "polkadot-node-primitives", + "polkadot-primitives", + "rand 0.8.5", + "sc-authority-discovery", + "sc-network", + "strum 0.24.1", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-primitives" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "bounded-vec", + "futures", + "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-primitives", + "schnorrkel", + "serde", + "sp-application-crypto", + "sp-consensus-babe", + "sp-core", + "sp-keystore", + "sp-maybe-compressed-blob", + "sp-runtime", + "thiserror", + "zstd 0.12.4", +] + +[[package]] +name = "polkadot-node-subsystem-types" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "async-trait", + "derive_more", + "futures", + "orchestra", + "polkadot-node-jaeger", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-primitives", + "polkadot-statement-table", + "sc-network", + "sc-transaction-pool-api", + "smallvec", + "sp-api", + "sp-authority-discovery", + "sp-consensus-babe", + "substrate-prometheus-endpoint", + "thiserror", +] [[package]] -name = "polkadot-core-primitives" +name = "polkadot-overseer" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ - "parity-scale-codec", - "scale-info", + "async-trait", + "futures", + "futures-timer", + "orchestra", + "parking_lot 0.12.1", + "polkadot-node-metrics", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem-types", + "polkadot-primitives", + "sc-client-api", + "schnellru", + "sp-api", "sp-core", - "sp-runtime", - "sp-std", + "tikv-jemalloc-ctl", + "tracing-gum", ] [[package]] name = "polkadot-parachain-primitives" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "bounded-collections", "derive_more", @@ -6047,7 +6472,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "bitvec", "hex-literal 0.4.1", @@ -6073,7 +6498,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "bitvec", "frame-benchmarking", @@ -6118,7 +6543,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "polkadot-primitives", @@ -6132,7 +6557,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "bs58 0.5.0", "frame-benchmarking", @@ -6145,7 +6570,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "bitflags 1.3.2", "bitvec", @@ -6187,6 +6612,16 @@ dependencies = [ "staging-xcm-executor", ] +[[package]] +name = "polkadot-statement-table" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "parity-scale-codec", + "polkadot-primitives", + "sp-core", +] + [[package]] name = "polling" version = "2.8.0" @@ -6320,13 +6755,29 @@ dependencies = [ ] [[package]] -name = "proc-macro-crate" -version = "1.1.3" +name = "prioritized-metered-channel" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "382698e48a268c832d0b181ed438374a6bb708a82a8ca273bb0f61c74cf209c4" dependencies = [ + "coarsetime", + "crossbeam-queue", + "derive_more", + "futures", + "futures-timer", + "nanorand", "thiserror", - "toml 0.5.11", + "tracing", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", ] [[package]] @@ -6878,7 +7329,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "polkadot-primitives", @@ -7157,7 +7608,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "log", "sp-core", @@ -7165,10 +7616,38 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sc-authority-discovery" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "async-trait", + "futures", + "futures-timer", + "ip_network", + "libp2p", + "log", + "multihash", + "parity-scale-codec", + "prost", + "prost-build", + "rand 0.8.5", + "sc-client-api", + "sc-network", + "sp-api", + "sp-authority-discovery", + "sp-blockchain", + "sp-core", + "sp-keystore", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", +] + [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "futures", "futures-timer", @@ -7191,7 +7670,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -7206,7 +7685,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -7225,7 +7704,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7236,7 +7715,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "array-bytes", "chrono", @@ -7275,7 +7754,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "fnv", "futures", @@ -7301,7 +7780,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "hash-db", "kvdb", @@ -7327,7 +7806,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "futures", @@ -7352,7 +7831,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "futures", @@ -7381,7 +7860,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "ahash 0.8.6", "array-bytes", @@ -7422,7 +7901,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "futures", @@ -7445,7 +7924,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -7467,7 +7946,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -7479,7 +7958,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "anyhow", "cfg-if", @@ -7496,7 +7975,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "ansi_term", "futures", @@ -7512,7 +7991,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "array-bytes", "parking_lot 0.12.1", @@ -7526,7 +8005,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "array-bytes", "async-channel", @@ -7567,7 +8046,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-channel", "cid", @@ -7587,7 +8066,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "bitflags 1.3.2", @@ -7604,7 +8083,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "ahash 0.8.6", "futures", @@ -7622,7 +8101,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "array-bytes", "async-channel", @@ -7643,7 +8122,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "array-bytes", "async-channel", @@ -7677,7 +8156,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "array-bytes", "futures", @@ -7695,7 +8174,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "array-bytes", "bytes", @@ -7729,7 +8208,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -7738,7 +8217,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "futures", "jsonrpsee", @@ -7769,7 +8248,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -7788,7 +8267,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "http", "jsonrpsee", @@ -7803,7 +8282,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "array-bytes", "futures", @@ -7831,7 +8310,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "directories", @@ -7895,7 +8374,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "log", "parity-scale-codec", @@ -7906,7 +8385,7 @@ dependencies = [ [[package]] name = "sc-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "log", "parity-db", @@ -7925,7 +8404,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "futures", "libc", @@ -7944,7 +8423,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "chrono", "futures", @@ -7963,7 +8442,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "ansi_term", "atty", @@ -7992,7 +8471,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8003,7 +8482,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "futures", @@ -8029,7 +8508,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "futures", @@ -8045,7 +8524,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-channel", "futures", @@ -8467,7 +8946,7 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "slot-range-helper" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "enumn", "parity-scale-codec", @@ -8545,7 +9024,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "hash-db", "log", @@ -8566,11 +9045,11 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "Inflector", "blake2", - "expander", + "expander 2.0.0", "proc-macro-crate", "proc-macro2", "quote", @@ -8580,7 +9059,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "23.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "scale-info", @@ -8593,7 +9072,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "16.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "integer-sqrt", "num-traits", @@ -8607,7 +9086,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "scale-info", @@ -8620,7 +9099,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "sp-api", "sp-inherents", @@ -8631,7 +9110,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "futures", "log", @@ -8649,7 +9128,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "futures", @@ -8664,7 +9143,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "parity-scale-codec", @@ -8681,7 +9160,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "parity-scale-codec", @@ -8700,7 +9179,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "finality-grandpa", "log", @@ -8718,7 +9197,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "scale-info", @@ -8730,7 +9209,7 @@ dependencies = [ [[package]] name = "sp-core" version = "21.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "array-bytes", "arrayvec 0.7.4", @@ -8777,7 +9256,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "9.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "blake2b_simd", "byteorder", @@ -8790,7 +9269,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "9.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "quote", "sp-core-hashing", @@ -8800,7 +9279,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -8809,7 +9288,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "proc-macro2", "quote", @@ -8819,7 +9298,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.19.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "environmental", "parity-scale-codec", @@ -8830,7 +9309,7 @@ dependencies = [ [[package]] name = "sp-genesis-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "serde_json", "sp-api", @@ -8841,7 +9320,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -8855,7 +9334,7 @@ dependencies = [ [[package]] name = "sp-io" version = "23.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "bytes", "ed25519-dalek", @@ -8879,7 +9358,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "24.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "lazy_static", "sp-core", @@ -8890,7 +9369,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.27.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "parking_lot 0.12.1", @@ -8902,7 +9381,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "thiserror", "zstd 0.12.4", @@ -8911,7 +9390,7 @@ dependencies = [ [[package]] name = "sp-metadata-ir" version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-metadata", "parity-scale-codec", @@ -8922,7 +9401,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "scale-info", @@ -8936,7 +9415,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "sp-api", "sp-core", @@ -8946,7 +9425,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "backtrace", "lazy_static", @@ -8956,7 +9435,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "rustc-hash", "serde", @@ -8966,7 +9445,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "24.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "either", "hash256-std-hasher", @@ -8988,7 +9467,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -9006,7 +9485,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "Inflector", "proc-macro-crate", @@ -9018,7 +9497,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "scale-info", @@ -9033,7 +9512,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", @@ -9047,7 +9526,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.28.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "hash-db", "log", @@ -9068,7 +9547,7 @@ dependencies = [ [[package]] name = "sp-statement-store" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "aes-gcm 0.10.3", "curve25519-dalek 4.1.1", @@ -9092,12 +9571,12 @@ dependencies = [ [[package]] name = "sp-std" version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" [[package]] name = "sp-storage" version = "13.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "impl-serde", "parity-scale-codec", @@ -9110,7 +9589,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "parity-scale-codec", @@ -9123,7 +9602,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "10.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "sp-std", @@ -9135,7 +9614,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "sp-api", "sp-runtime", @@ -9144,7 +9623,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "parity-scale-codec", @@ -9159,7 +9638,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "22.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "ahash 0.8.6", "hash-db", @@ -9182,7 +9661,7 @@ dependencies = [ [[package]] name = "sp-version" version = "22.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "impl-serde", "parity-scale-codec", @@ -9199,7 +9678,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -9210,7 +9689,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -9223,7 +9702,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "20.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "parity-scale-codec", "scale-info", @@ -9302,7 +9781,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "staging-xcm" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "bounded-collections", "derivative", @@ -9319,7 +9798,7 @@ dependencies = [ [[package]] name = "staging-xcm-builder" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "frame-system", @@ -9341,7 +9820,7 @@ dependencies = [ [[package]] name = "staging-xcm-executor" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "environmental", "frame-benchmarking", @@ -9474,12 +9953,12 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -9498,7 +9977,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "hyper", "log", @@ -9510,7 +9989,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "jsonrpsee", @@ -9523,7 +10002,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "ansi_term", "build-helper", @@ -9739,15 +10218,24 @@ dependencies = [ name = "sygma-xcm-bridge" version = "0.3.0" dependencies = [ + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "cumulus-primitives-utility", "frame-support", "frame-system", "pallet-assets", "pallet-balances", + "pallet-message-queue", + "pallet-xcm", "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "polkadot-runtime-parachains", "scale-info", + "sp-core", "sp-io", "sp-runtime", "sp-std", @@ -9756,6 +10244,7 @@ dependencies = [ "staging-xcm-executor", "sygma-bridge-forwarder", "sygma-traits", + "xcm-simulator", ] [[package]] @@ -9898,6 +10387,30 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "thrift" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b82ca8f46f95b3ce96081fe3dd89160fdea970c254bb72925255d1b62aae692e" +dependencies = [ + "byteorder", + "integer-encoding", + "log", + "ordered-float", + "threadpool", +] + +[[package]] +name = "tikv-jemalloc-ctl" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619bfed27d807b54f7f776b9430d4f8060e66ee138a28632ca898584d462c31c" +dependencies = [ + "libc", + "paste", + "tikv-jemalloc-sys", +] + [[package]] name = "tikv-jemalloc-sys" version = "0.5.4+5.3.0-patched" @@ -10195,6 +10708,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "tracing-gum" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "coarsetime", + "polkadot-node-jaeger", + "polkadot-primitives", + "tracing", + "tracing-gum-proc-macro", +] + +[[package]] +name = "tracing-gum-proc-macro" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "expander 2.0.0", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "tracing-log" version = "0.1.4" @@ -10316,7 +10853,7 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "async-trait", "clap", @@ -11174,7 +11711,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "frame-support", "polkadot-primitives", @@ -11486,7 +12023,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#f60318f68687e601c47de5ad5ca88e2c3f8139a7" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" dependencies = [ "Inflector", "proc-macro2", @@ -11494,6 +12031,24 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "xcm-simulator" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" +dependencies = [ + "frame-support", + "parity-scale-codec", + "paste", + "polkadot-core-primitives", + "polkadot-parachain-primitives", + "polkadot-runtime-parachains", + "sp-io", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + [[package]] name = "yamux" version = "0.10.2" diff --git a/xcm-bridge/Cargo.toml b/xcm-bridge/Cargo.toml index afcca5b2..249df3a8 100644 --- a/xcm-bridge/Cargo.toml +++ b/xcm-bridge/Cargo.toml @@ -11,11 +11,12 @@ scale-info = { version = "2.5.0", default-features = false, features = ["derive" # Substrate frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } -sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } # Polkadot xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } @@ -33,13 +34,34 @@ sygma-bridge-forwarder = { path = "../bridge-forwarder", default-features = fals [dev-dependencies] # Substrate -sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } + +# Polkadot +xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +xcm-simulator = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } + +# Cumulus +cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +# Local sygma-traits = { path = "../traits" } [features] @@ -49,7 +71,9 @@ std = [ "scale-info/std", "frame-support/std", "frame-system/std", + "sp-runtime/std", "sp-std/std", + "sp-core/full_crypto", "xcm/std", "xcm-builder/std", "xcm-executor/std", @@ -60,7 +84,6 @@ std = [ "cumulus-pallet-xcm/std", "sygma-traits/std", "sygma-bridge-forwarder/std", - ] runtime-benchmarks = [ 'frame-support/runtime-benchmarks', diff --git a/xcm-bridge/src/mock.rs b/xcm-bridge/src/mock.rs index 1cc3d655..ea7a692c 100644 --- a/xcm-bridge/src/mock.rs +++ b/xcm-bridge/src/mock.rs @@ -3,6 +3,8 @@ #![cfg(test)] +mod relay; + use frame_support::{construct_runtime, pallet_prelude::ConstU32, parameter_types, sp_runtime::{ AccountId32, BuildStorage, diff --git a/xcm-bridge/src/mock/relay.rs b/xcm-bridge/src/mock/relay.rs new file mode 100644 index 00000000..fc86286c --- /dev/null +++ b/xcm-bridge/src/mock/relay.rs @@ -0,0 +1,239 @@ +use cumulus_primitives_core::ParaId; +use frame_support::{ + construct_runtime, parameter_types, + traits::{Everything, ProcessMessage, ProcessMessageError}, + weights::{IdentityFee, Weight, WeightMeter}, +}; +use frame_support::traits::{ConstU32, Nothing}; +use frame_system::EnsureRoot; +use polkadot_runtime_parachains::{ + configuration, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, shared, +}; +use sp_core::H256; +use sp_runtime::{AccountId32, traits::IdentityLookup}; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, + IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, + TakeWeightCredit, UsingComponents, +}; +use xcm_executor::{Config, traits::WithOriginFilter, XcmExecutor}; + +pub type AccountId = AccountId32; +pub type Balance = u128; + +type Block = frame_system::mocking::MockBlock; + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<2>; +} + +parameter_types! { + pub ExistentialDeposit: Balance = 1; + pub const MaxLocks: u32 = 50; + pub const MaxReserves: u32 = 50; +} + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxHolds = ConstU32<1>; + type MaxFreezes = ConstU32<1>; + type RuntimeHoldReason = (); +} + +impl shared::Config for Runtime {} + +impl configuration::Config for Runtime { + type WeightInfo = configuration::TestWeightInfo; +} + +parameter_types! { + pub RooLocation: MultiLocation = Here.into(); + pub const RococoNetwork: NetworkId = NetworkId::Rococo; + pub UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(RococoNetwork::get())); +} + +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, +); + +pub type LocalAssetTransactor = +XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; + + +type LocalOriginConverter = ( + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, +); + +pub type XcmRouter = super::RelayChainXcmRouter; +pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom); + +parameter_types! { + pub Rococo: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(RooLocation::get()) }); + pub Statemine: MultiLocation = Parachain(3).into(); + pub KusamaForStatemine: (MultiAssetFilter, MultiLocation) = (Kusama::get(), Statemine::get()); +} + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(10, 10); + pub const BaseXcmWeight: Weight = Weight::from_parts(100_000_000, 100_000_000); + pub const MaxInstructions: u32 = 100; + pub const MaxAssetsIntoHolding: u32 = 64; +} + +pub struct XcmConfig; + +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = UsingComponents, RooLocation, AccountId, Balances, ()>; + type ResponseHandler = (); + type AssetTrap = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = WithOriginFilter; + type SafeCallFilter = Everything; + type Aliasers = (); +} + +pub type LocalOriginToLocation = SignedToAccountId32; + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = pallet_xcm::TestWeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type AdminOrigin = EnsureRoot; +} + +impl origin::Config for Runtime {} + +parameter_types! { + /// Amount of weight that can be spent per block to service messages. + pub MessageQueueServiceWeight: Weight = Weight::from_parts(1_000_000_000, 1_000_000); + pub const MessageQueueHeapSize: u32 = 65_536; + pub const MessageQueueMaxStale: u32 = 16; +} + +pub struct MessageProcessor; + +impl ProcessMessage for MessageProcessor { + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + xcm_builder::ProcessXcmMessage::, RuntimeCall>::process_message( + message, + Junction::Parachain(para.into()), + meter, + id, + ) + } +} + +impl pallet_message_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type WeightInfo = (); + type QueuePausedQuery = (); +} + +construct_runtime!( + pub struct Runtime { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + ParasOrigin: origin::{Pallet, Origin}, + XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin}, + MessageQueue: pallet_message_queue::{Pallet, Event}, + } +); + + From 771cf13fe0094bb69159e8600eae6e7231741248 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Wed, 10 Jan 2024 11:47:21 -0500 Subject: [PATCH 19/30] add parachain setup for unit test --- Cargo.lock | 2 + xcm-bridge/Cargo.toml | 4 +- xcm-bridge/src/{mock.rs => mock/mod.rs} | 127 +++++++++++++++++++-- xcm-bridge/src/mock/para.rs | 145 ++++++++++++++++++++++++ xcm-bridge/src/mock/relay.rs | 22 ++-- 5 files changed, 279 insertions(+), 21 deletions(-) rename xcm-bridge/src/{mock.rs => mock/mod.rs} (74%) create mode 100644 xcm-bridge/src/mock/para.rs diff --git a/Cargo.lock b/Cargo.lock index 06b0fa3a..664b418d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10229,6 +10229,7 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-message-queue", + "pallet-parachain-info", "pallet-xcm", "parity-scale-codec", "polkadot-parachain-primitives", @@ -10242,6 +10243,7 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", + "sygma-bridge", "sygma-bridge-forwarder", "sygma-traits", "xcm-simulator", diff --git a/xcm-bridge/Cargo.toml b/xcm-bridge/Cargo.toml index 249df3a8..2d0f91d5 100644 --- a/xcm-bridge/Cargo.toml +++ b/xcm-bridge/Cargo.toml @@ -46,9 +46,9 @@ pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk.git", # Polkadot xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +xcm-simulator = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } -xcm-simulator = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } @@ -63,6 +63,8 @@ cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk # Local sygma-traits = { path = "../traits" } +pallet-parachain-info = { path = "../parachain-info" } +sygma-bridge = { path = "../bridge" } [features] default = ["std"] diff --git a/xcm-bridge/src/mock.rs b/xcm-bridge/src/mock/mod.rs similarity index 74% rename from xcm-bridge/src/mock.rs rename to xcm-bridge/src/mock/mod.rs index ea7a692c..0d4e3df2 100644 --- a/xcm-bridge/src/mock.rs +++ b/xcm-bridge/src/mock/mod.rs @@ -3,33 +3,37 @@ #![cfg(test)] -mod relay; - use frame_support::{construct_runtime, pallet_prelude::ConstU32, parameter_types, sp_runtime::{ AccountId32, BuildStorage, Perbill, testing::H256, traits::{BlakeTwo256, IdentityLookup}, }, traits::{AsEnsureOriginWithArg, ConstU128, Everything, Nothing}}; use frame_system::{EnsureSigned, self as system}; +use polkadot_parachain_primitives::primitives::Sibling; +use sp_io::TestExternalities; use xcm::latest::{prelude::*, Weight as XCMWeight}; use xcm_builder::{AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit}; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; +use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; use sygma_bridge::XCMAssetTransactor; +mod relay; +mod para; + type Block = frame_system::mocking::MockBlock; pub(crate) type Balance = u128; -pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub type AccountId = AccountId32; -construct_runtime! ( +construct_runtime!( pub enum Runtime { - System: frame_system, - CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Assets: pallet_assets::{Pallet, Call, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Storage, Event} = 5, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, + SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Storage, Event}, SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Call, Storage, Event}, } ); @@ -43,7 +47,6 @@ parameter_types! { } parameter_types! { - // Make sure put same value with `construct_runtime` pub const XcmBridgePalletIndex: u8 = 6; pub RegisteredExtrinsics: Vec<(u8, Vec)> = [ (XcmBridgePalletIndex::get(), b"transfer".to_vec()), @@ -122,12 +125,12 @@ impl pallet_assets::Config for Runtime { type Freezer = (); type Extra = (); type CallbackHandle = (); - type WeightInfo = pallet_assets::weights::SubstrateWeight; + type WeightInfo = pallet_assets::weights::SubstrateWeight; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } -impl xcm_bridge::Config for Runtime { +impl sygma_xcm_bridge::Config for Runtime { type RuntimeEvent = RuntimeEvent; type PalletIndex = XcmBridgePalletIndex; @@ -257,3 +260,105 @@ pub fn assert_events(mut expected: Vec) { assert_eq!(next, evt, "Events don't match"); } } + +pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); +pub const ENDOWED_BALANCE: u128 = 100_000_000; +pub const TEST_THRESHOLD: u32 = 2; + +decl_test_parachain! { + pub struct ParaA { + Runtime = para::Runtime, + XcmpMessageHandler = para::XcmpQueue, + DmpMessageHandler = para::DmpQueue, + new_ext = para_ext(1), + } +} + +decl_test_parachain! { + pub struct ParaB { + Runtime = para::Runtime, + XcmpMessageHandler = para::XcmpQueue, + DmpMessageHandler = para::DmpQueue, + new_ext = para_ext(2), + } +} + +decl_test_parachain! { + pub struct ParaC { + Runtime = para_teleport::Runtime, + XcmpMessageHandler = para::XcmpQueue, + DmpMessageHandler = para::DmpQueue, + new_ext = para_ext(3), + } +} + +decl_test_relay_chain! { + pub struct Relay { + Runtime = relay::Runtime, + RuntimeCall = relay::RuntimeCall, + RuntimeEvent = relay::RuntimeEvent, + XcmConfig = relay::XcmConfig, + MessageQueue = relay::MessageQueue, + System = relay::System, + new_ext = relay_ext(), + } +} + +decl_test_network! { + pub struct TestNet { + relay_chain = Relay, + parachains = vec![ + (1, ParaA), + (2, ParaB), + (3, ParaC), + ], + } +} + +pub fn para_ext(para_id: u32) -> TestExternalities { + use para::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + let parachain_info_config = pallet_parachain_info::GenesisConfig:: { + parachain_id: para_id.into(), + phantom: Default::default(), + }; + parachain_info_config.assimilate_storage(&mut t).unwrap(); + + // TODO: set up the init account token balance for unit test + pallet_balances::GenesisConfig:: { + balances: vec![ + (bridge_account, ENDOWED_BALANCE), + (ALICE, ENDOWED_BALANCE), + (BOB, ENDOWED_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +pub fn relay_ext() -> sp_io::TestExternalities { + use relay::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default() + .build_storage() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(ALICE, 1_000)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} \ No newline at end of file diff --git a/xcm-bridge/src/mock/para.rs b/xcm-bridge/src/mock/para.rs new file mode 100644 index 00000000..4ead7214 --- /dev/null +++ b/xcm-bridge/src/mock/para.rs @@ -0,0 +1,145 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +use cumulus_primitives_core::{ChannelStatus, GetChannelInfo, ParaId}; +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything} +}; +use frame_support::traits::ConstU64; +use frame_system::EnsureRoot; +use sp_core::{crypto::AccountId32, H256}; +use sp_runtime::traits::IdentityLookup; +use xcm::latest::prelude::*; +use xcm_executor::XcmExecutor; +use crate::mock::{XcmConfig, XcmOriginToTransactDispatchOrigin}; + +construct_runtime!( + pub struct Runtime { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, + Assets: pallet_assets::{Pallet, Call, Storage, Event}, + + ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, + ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Storage, Config}, + + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event}, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event}, + } +); + +type Block = frame_system::mocking::MockBlock; + +pub(crate) type Balance = u128; + +pub type AccountId = AccountId32; + +impl frame_system::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type MaxConsumers = ConstU32<16>; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 1; // 1 Unit deposit to create asset + pub const ApprovalDeposit: Balance = 1; + pub const AssetsStringLimit: u32 = 50; + pub const MetadataDepositBase: Balance = 1; + pub const MetadataDepositPerByte: Balance = 1; +} + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxHolds = ConstU32<1>; + type MaxFreezes = ConstU32<1>; + type RuntimeHoldReason = (); +} + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + type AssetDeposit = ExistentialDeposit; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type CallbackHandle = (); + type WeightInfo = (); + type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +impl pallet_parachain_info::Config for Runtime {} + +pub struct ChannelInfo; + +impl GetChannelInfo for ChannelInfo { + fn get_channel_status(_id: ParaId) -> ChannelStatus { + ChannelStatus::Ready(10, 10) + } + fn get_channel_max(_id: ParaId) -> Option { + Some(usize::max_value()) + } +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; + type ChannelInfo = ChannelInfo; + type VersionWrapper = (); + type ExecuteOverweightOrigin = EnsureRoot; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = (); + type PriceForSiblingDelivery = (); +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; + type ExecuteOverweightOrigin = EnsureRoot; +} diff --git a/xcm-bridge/src/mock/relay.rs b/xcm-bridge/src/mock/relay.rs index fc86286c..4a624936 100644 --- a/xcm-bridge/src/mock/relay.rs +++ b/xcm-bridge/src/mock/relay.rs @@ -1,3 +1,6 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + use cumulus_primitives_core::ParaId; use frame_support::{ construct_runtime, parameter_types, @@ -22,6 +25,16 @@ use xcm_builder::{ }; use xcm_executor::{Config, traits::WithOriginFilter, XcmExecutor}; +construct_runtime!( + pub struct Runtime { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + ParasOrigin: origin::{Pallet, Origin}, + XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin}, + MessageQueue: pallet_message_queue::{Pallet, Event}, + } +); + pub type AccountId = AccountId32; pub type Balance = u128; @@ -226,14 +239,5 @@ impl pallet_message_queue::Config for Runtime { type QueuePausedQuery = (); } -construct_runtime!( - pub struct Runtime { - System: frame_system::{Pallet, Call, Storage, Config, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - ParasOrigin: origin::{Pallet, Origin}, - XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin}, - MessageQueue: pallet_message_queue::{Pallet, Event}, - } -); From 674b1bc7ca2f28bb9be2711ddce870a430015569 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Fri, 12 Jan 2024 12:04:16 -0500 Subject: [PATCH 20/30] add xcm bridge unit tests --- xcm-bridge/src/lib.rs | 135 ++++++++++++++++++++++++++++++++++++- xcm-bridge/src/mock/mod.rs | 26 ++++--- 2 files changed, 144 insertions(+), 17 deletions(-) diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 3c7a0c9e..d00a5ef7 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -42,11 +42,11 @@ pub mod pallet { } pub enum TransferKind { - /// Transfer self reserve asset. + /// Transfer self reserve asset. assets reserved by the origin chain SelfReserveAsset, - /// To reserve location. + /// To reserve location. assets reserved by the dest chain ToReserve, - /// To non-reserve location. + /// To non-reserve location. assets not reserved by the dest chain ToNonReserve, } @@ -317,5 +317,134 @@ pub mod pallet { } } } + + #[cfg(test)] + mod test { + use frame_support::assert_ok; + + use crate::mock::{ + ALICE, BOB, ENDOWED_BALANCE, + ParaA, ParaAssets, ParaB, ParaBalances, TestNet, + }; + use crate::mock::para::Runtime; + use sygma_bridge::mock::UsdtLocation; + + #[test] + fn test_transfer_self_reserve_asset_to_parachain() { + TestNet::reset(); + + ParaA::execute_with(|| { + let bridge = Bridge::::new(); + // transfer parachain A native asset from Alice to parachain B on Bob + assert_ok!(bridge.transfer(ALICE.into(), + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), + MultiLocation::new( + 1, + X2( + Parachain(2u32.into()), + Junction::AccountId32 { + network: None, + id: BOB.into(), + }, + ), + ) + )); + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10); + }); + + ParaB::execute_with(|| { + assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 10); + }); + } + + #[test] + fn test_transfer_to_reserve_to_parachain() { + TestNet::reset(); + + let para_a_location = MultiLocation { + parents: 1, + interior: X1(Parachain(1)), + }; + + // Prepare step + // sending parachainB native asset to parachainA + ParaB::execute_with(|| { + let bridge = Bridge::::new(); + assert_ok!(bridge.transfer( + ALICE.into(), + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), + MultiLocation::new( + 1, + X2( + Parachain(1u32.into()), + Junction::AccountId32 { + network: None, + id: BOB.into() + } + ) + ) + )); + + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10); + }); + // Bob on parachainA should have parachainB's native asset + ParaA::execute_with(|| { + assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 10); + }); + + // sending parachainB's native asset from parachainA back to parachainB + ParaA::execute_with(|| { + let bridge = Bridge::::new(); + assert_ok!(bridge.transfer( + BOB.into(), + (Concrete(para_a_location.clone()), Fungible(5u128)).into(), // sending 5 tokens + MultiLocation::new( + 1, + X2( + Parachain(2u32.into()), + Junction::AccountId32 { + network: None, + id: ALICE.into() + } + ) + ) + )); + + assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 10 - 5); + }); + ParaA::execute_with(|| { + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10 + 5); + }); + } + + #[test] + fn test_transfer_to_non_reserve_to_parachain() { + TestNet::reset(); + + // send USDT token from parachainA to parachainB + ParaA::execute_with(|| { + let bridge = Bridge::::new(); + assert_ok!(bridge.transfer(ALICE.into(), + (Concrete(UsdtLocation::get().into()), Fungible(10u128)).into(), + MultiLocation::new( + 1, + X2( + Parachain(2u32.into()), + Junction::AccountId32 { + network: None, + id: BOB.into(), + }, + ), + ) + )); + assert_eq!(ParaAssets::balance(&ALICE), ENDOWED_BALANCE - 10); + }); + + ParaB::execute_with(|| { + assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 10); + }); + + } + } } diff --git a/xcm-bridge/src/mock/mod.rs b/xcm-bridge/src/mock/mod.rs index 0d4e3df2..00c42ec8 100644 --- a/xcm-bridge/src/mock/mod.rs +++ b/xcm-bridge/src/mock/mod.rs @@ -18,8 +18,10 @@ use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chai use sygma_bridge::XCMAssetTransactor; +use crate as sygma_xcm_bridge; + mod relay; -mod para; +pub(crate) mod para; type Block = frame_system::mocking::MockBlock; @@ -284,15 +286,6 @@ decl_test_parachain! { } } -decl_test_parachain! { - pub struct ParaC { - Runtime = para_teleport::Runtime, - XcmpMessageHandler = para::XcmpQueue, - DmpMessageHandler = para::DmpQueue, - new_ext = para_ext(3), - } -} - decl_test_relay_chain! { pub struct Relay { Runtime = relay::Runtime, @@ -311,7 +304,6 @@ decl_test_network! { parachains = vec![ (1, ParaA), (2, ParaB), - (3, ParaC), ], } } @@ -329,10 +321,8 @@ pub fn para_ext(para_id: u32) -> TestExternalities { }; parachain_info_config.assimilate_storage(&mut t).unwrap(); - // TODO: set up the init account token balance for unit test pallet_balances::GenesisConfig:: { balances: vec![ - (bridge_account, ENDOWED_BALANCE), (ALICE, ENDOWED_BALANCE), (BOB, ENDOWED_BALANCE), ], @@ -340,6 +330,14 @@ pub fn para_ext(para_id: u32) -> TestExternalities { .assimilate_storage(&mut t) .unwrap(); + pallet_assets::GenesisConfig:: { + assets: vec![(0, ALICE, false, 1)], + metadata: vec![(0, "USDT".into(), "USDT".into(), 6)], + accounts: vec![(0, ALICE, ENDOWED_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext @@ -353,7 +351,7 @@ pub fn relay_ext() -> sp_io::TestExternalities { .unwrap(); pallet_balances::GenesisConfig:: { - balances: vec![(ALICE, 1_000)], + balances: vec![(ALICE, ENDOWED_BALANCE)], } .assimilate_storage(&mut t) .unwrap(); From c310a8915eb2cc749b9ba6caca3edbec6729e2c6 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Mon, 15 Jan 2024 12:04:48 -0500 Subject: [PATCH 21/30] adject the local mock runtime impl for xcm bridge --- Cargo.lock | 1 - bridge/src/mock.rs | 4 +- xcm-bridge/Cargo.toml | 1 - xcm-bridge/src/lib.rs | 3 +- xcm-bridge/src/mock/mod.rs | 95 ++++++++++++++++++++++++++++++------- xcm-bridge/src/mock/para.rs | 1 - 6 files changed, 80 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 664b418d..317f4fcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10243,7 +10243,6 @@ dependencies = [ "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", - "sygma-bridge", "sygma-bridge-forwarder", "sygma-traits", "xcm-simulator", diff --git a/bridge/src/mock.rs b/bridge/src/mock.rs index ce172c9a..aef7c56c 100644 --- a/bridge/src/mock.rs +++ b/bridge/src/mock.rs @@ -48,8 +48,8 @@ frame_support::construct_runtime!( SygmaBridge: sygma_bridge::{Pallet, Call, Storage, Event} = 6, SygmaPercentageFeeHandler: sygma_percentage_feehandler::{Pallet, Call, Storage, Event} = 7, SygmaFeeHandlerRouter: sygma_fee_handler_router::{Pallet, Call, Storage, Event} = 8, - SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Call, Storage, Event} = 9, - SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Call, Storage, Event} = 10, + SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Event} = 9, + SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Event} = 10, } ); diff --git a/xcm-bridge/Cargo.toml b/xcm-bridge/Cargo.toml index 2d0f91d5..7387b292 100644 --- a/xcm-bridge/Cargo.toml +++ b/xcm-bridge/Cargo.toml @@ -64,7 +64,6 @@ cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk # Local sygma-traits = { path = "../traits" } pallet-parachain-info = { path = "../parachain-info" } -sygma-bridge = { path = "../bridge" } [features] default = ["std"] diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index d00a5ef7..ed32d91c 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -324,10 +324,9 @@ pub mod pallet { use crate::mock::{ ALICE, BOB, ENDOWED_BALANCE, - ParaA, ParaAssets, ParaB, ParaBalances, TestNet, + ParaA, ParaAssets, ParaB, ParaBalances, TestNet, UsdtLocation }; use crate::mock::para::Runtime; - use sygma_bridge::mock::UsdtLocation; #[test] fn test_transfer_self_reserve_asset_to_parachain() { diff --git a/xcm-bridge/src/mock/mod.rs b/xcm-bridge/src/mock/mod.rs index 00c42ec8..4197d1f8 100644 --- a/xcm-bridge/src/mock/mod.rs +++ b/xcm-bridge/src/mock/mod.rs @@ -3,6 +3,9 @@ #![cfg(test)] +use std::marker::PhantomData; +use std::result; + use frame_support::{construct_runtime, pallet_prelude::ConstU32, parameter_types, sp_runtime::{ AccountId32, BuildStorage, @@ -13,15 +16,13 @@ use polkadot_parachain_primitives::primitives::Sibling; use sp_io::TestExternalities; use xcm::latest::{prelude::*, Weight as XCMWeight}; use xcm_builder::{AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit}; -use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; +use xcm_executor::{Config, traits::{Error as ExecutionError, MatchesFungibles, WithOriginFilter}, XcmExecutor}; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; -use sygma_bridge::XCMAssetTransactor; - use crate as sygma_xcm_bridge; -mod relay; -pub(crate) mod para; +pub mod relay; +pub mod para; type Block = frame_system::mocking::MockBlock; @@ -34,9 +35,10 @@ construct_runtime!( System: frame_system::{Pallet, Call, Storage, Config, Event}, Assets: pallet_assets::{Pallet, Call, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, - SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Storage, Event}, - SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Call, Storage, Event}, + SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Event}, + SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Event}, } ); @@ -109,10 +111,12 @@ parameter_types! { pub const MetadataDepositPerByte: Balance = 1; } +pub type AssetId = u32; + impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; - type AssetId = u32; + type AssetId = AssetId; type AssetIdParameter = codec::Compact; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; @@ -141,17 +145,20 @@ impl sygma_xcm_bridge::Config for Runtime { type SelfLocation = SelfLocation; } +impl sygma_bridge_forwarder::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SygmaBridge = (); + type XCMBridge = (); +} + +impl pallet_parachain_info::Config for Runtime {} + pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; - type AssetTransactor = XCMAssetTransactor< - CurrencyTransactor, - FungiblesTransactor, - SygmaXcmBridge, - SygmaBridgeForwarder, - >; + type AssetTransactor = (CurrencyTransactor, FungiblesTransactor); type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = NativeAsset; type IsTeleporter = (); @@ -209,6 +216,42 @@ parameter_types! { pub const MaxInstructions: u32 = 100; } +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +parameter_types! { + pub NativeLocation: MultiLocation = MultiLocation::here(); + pub UsdtAssetId: AssetId = 0; + pub UsdtLocation: MultiLocation = MultiLocation::new( + 1, + X3( + Parachain(2005), + slice_to_generalkey(b"sygma"), + slice_to_generalkey(b"usdt"), + ), + ); + pub CheckingAccount: AccountId32 = AccountId32::new([102u8; 32]); +} + +pub struct SimpleForeignAssetConverter(PhantomData<()>); + +impl MatchesFungibles for SimpleForeignAssetConverter { + fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), ExecutionError> { + match (&a.fun, &a.id) { + (Fungible(ref amount), Concrete(ref id)) => { + if id == &UsdtLocation::get() { + Ok((UsdtAssetId::get(), *amount)) + } else { + Err(ExecutionError::AssetNotHandled) + } + } + _ => Err(ExecutionError::AssetNotHandled), + } + } +} + pub type CurrencyTransactor = CurrencyAdapter< // Use this currency: Balances, @@ -227,7 +270,7 @@ pub type FungiblesTransactor = FungiblesAdapter< // Use this fungibles implementation: Assets, // Use this currency when it is a fungible asset matching the given location or name: - sygma_bridge::SimpleForeignAssetConverter, + SimpleForeignAssetConverter, // Convert an XCM MultiLocation into a local account id: LocationToAccountId, // Our chain's account ID type (we can't get away without mentioning it explicitly): @@ -239,11 +282,11 @@ pub type FungiblesTransactor = FungiblesAdapter< >; parameter_types! { - pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::get().into()))); + pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))); } pub fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext @@ -253,7 +296,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { // include the most recent event, but do not have to include every past event. pub fn assert_events(mut expected: Vec) { let mut actual: Vec = - system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); expected.reverse(); @@ -268,6 +311,9 @@ pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); pub const ENDOWED_BALANCE: u128 = 100_000_000; pub const TEST_THRESHOLD: u32 = 2; +pub type ParaBalances = pallet_balances::Pallet; +pub type ParaAssets = pallet_assets::Pallet; + decl_test_parachain! { pub struct ParaA { Runtime = para::Runtime, @@ -359,4 +405,17 @@ pub fn relay_ext() -> sp_io::TestExternalities { let mut ext = sp_io::TestExternalities::new(t); ext.execute_with(|| System::set_block_number(1)); ext +} + +pub fn slice_to_generalkey(key: &[u8]) -> Junction { + let len = key.len(); + assert!(len <= 32); + GeneralKey { + length: len as u8, + data: { + let mut data = [0u8; 32]; + data[..len].copy_from_slice(key); + data + }, + } } \ No newline at end of file diff --git a/xcm-bridge/src/mock/para.rs b/xcm-bridge/src/mock/para.rs index 4ead7214..710f4ab5 100644 --- a/xcm-bridge/src/mock/para.rs +++ b/xcm-bridge/src/mock/para.rs @@ -20,7 +20,6 @@ construct_runtime!( Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, Assets: pallet_assets::{Pallet, Call, Storage, Event}, - ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Storage, Config}, XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event}, From e0971fc3748b04069e63f53d1287dc7b686c0d63 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Wed, 17 Jan 2024 11:06:51 -0500 Subject: [PATCH 22/30] fix the xcm bridge runtime and add event --- Cargo.lock | 476 +---------------------------------- xcm-bridge/Cargo.toml | 1 - xcm-bridge/src/lib.rs | 107 ++++++-- xcm-bridge/src/mock/mod.rs | 312 +---------------------- xcm-bridge/src/mock/para.rs | 238 +++++++++++++++++- xcm-bridge/src/mock/relay.rs | 2 +- 6 files changed, 322 insertions(+), 814 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 317f4fcd..fb7261c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -920,15 +920,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bounded-vec" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68534a48cbf63a4b1323c433cf21238c9ec23711e0df13b08c33e5c2082663ce" -dependencies = [ - "thiserror", -] - [[package]] name = "bs58" version = "0.4.0" @@ -1224,18 +1215,6 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" -[[package]] -name = "coarsetime" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71367d3385c716342014ad17e3d19f7788ae514885a1f4c24f500260fb365e1a" -dependencies = [ - "libc", - "once_cell", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - [[package]] name = "codespan-reporting" version = "0.11.1" @@ -1532,15 +1511,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -1643,47 +1613,6 @@ dependencies = [ "staging-xcm", ] -[[package]] -name = "cumulus-pallet-parachain-system" -version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "bytes", - "cumulus-pallet-parachain-system-proc-macro", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "environmental", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "polkadot-parachain-primitives", - "scale-info", - "sp-core", - "sp-externalities", - "sp-inherents", - "sp-io", - "sp-runtime", - "sp-state-machine", - "sp-std", - "sp-trie", - "sp-version", - "staging-xcm", - "trie-db", -] - -[[package]] -name = "cumulus-pallet-parachain-system-proc-macro" -version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "cumulus-pallet-xcm" version = "0.1.0" @@ -1738,29 +1667,6 @@ dependencies = [ "staging-xcm", ] -[[package]] -name = "cumulus-primitives-parachain-inherent" -version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "async-trait", - "cumulus-primitives-core", - "cumulus-relay-chain-interface", - "cumulus-test-relay-sproof-builder", - "parity-scale-codec", - "sc-client-api", - "scale-info", - "sp-api", - "sp-core", - "sp-inherents", - "sp-runtime", - "sp-state-machine", - "sp-std", - "sp-storage", - "sp-trie", - "tracing", -] - [[package]] name = "cumulus-primitives-utility" version = "0.1.0" @@ -1779,38 +1685,6 @@ dependencies = [ "staging-xcm-executor", ] -[[package]] -name = "cumulus-relay-chain-interface" -version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "async-trait", - "cumulus-primitives-core", - "futures", - "jsonrpsee-core", - "parity-scale-codec", - "polkadot-overseer", - "sc-client-api", - "sp-api", - "sp-blockchain", - "sp-state-machine", - "thiserror", -] - -[[package]] -name = "cumulus-test-relay-sproof-builder" -version = "0.1.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "cumulus-primitives-core", - "parity-scale-codec", - "polkadot-primitives", - "sp-runtime", - "sp-state-machine", - "sp-std", - "sp-trie", -] - [[package]] name = "curve25519-dalek" version = "2.1.3" @@ -2492,30 +2366,6 @@ dependencies = [ "futures", ] -[[package]] -name = "expander" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a718c0675c555c5f976fff4ea9e2c150fa06cefa201cadef87cfbf9324075881" -dependencies = [ - "blake3", - "fs-err", - "proc-macro2", - "quote", -] - -[[package]] -name = "expander" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3774182a5df13c3d1690311ad32fbe913feef26baba609fa2dd5f72042bd2ab6" -dependencies = [ - "blake2", - "fs-err", - "proc-macro2", - "quote", -] - [[package]] name = "expander" version = "2.0.0" @@ -2556,31 +2406,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" -[[package]] -name = "fatality" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad875162843b0d046276327afe0136e9ed3a23d5a754210fb6f1f33610d39ab" -dependencies = [ - "fatality-proc-macro", - "thiserror", -] - -[[package]] -name = "fatality-proc-macro" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5aa1e3ae159e592ad222dc90c5acbad632b527779ba88486abe92782ab268bd" -dependencies = [ - "expander 0.0.4", - "indexmap 1.9.3", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", - "thiserror", -] - [[package]] name = "fdlimit" version = "0.2.1" @@ -2947,7 +2772,7 @@ dependencies = [ "Inflector", "cfg-expr", "derive-syn-parse", - "expander 2.0.0", + "expander", "frame-support-procedural-tools", "itertools", "macro_magic", @@ -3779,12 +3604,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "integer-encoding" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" - [[package]] name = "integer-sqrt" version = "0.1.5" @@ -4936,17 +4755,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "mick-jaeger" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69672161530e8aeca1d1400fbf3f1a1747ff60ea604265a4e906c2442df20532" -dependencies = [ - "futures", - "rand 0.8.5", - "thrift", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -5117,12 +4925,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "nanorand" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" - [[package]] name = "netlink-packet-core" version = "0.4.2" @@ -5466,47 +5268,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "orchestra" -version = "0.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227585216d05ba65c7ab0a0450a3cf2cbd81a98862a54c4df8e14d5ac6adb015" -dependencies = [ - "async-trait", - "dyn-clonable", - "futures", - "futures-timer", - "orchestra-proc-macro", - "pin-project", - "prioritized-metered-channel", - "thiserror", - "tracing", -] - -[[package]] -name = "orchestra-proc-macro" -version = "0.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2871aadd82a2c216ee68a69837a526dfe788ecbe74c4c5038a6acdbff6653066" -dependencies = [ - "expander 0.0.6", - "itertools", - "petgraph", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ordered-float" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" -dependencies = [ - "num-traits", -] - [[package]] name = "p256" version = "0.11.1" @@ -6322,136 +6083,6 @@ dependencies = [ "sp-std", ] -[[package]] -name = "polkadot-node-jaeger" -version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "lazy_static", - "log", - "mick-jaeger", - "parity-scale-codec", - "parking_lot 0.12.1", - "polkadot-node-primitives", - "polkadot-primitives", - "sc-network", - "sp-core", - "thiserror", - "tokio", -] - -[[package]] -name = "polkadot-node-metrics" -version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "bs58 0.5.0", - "futures", - "futures-timer", - "log", - "parity-scale-codec", - "polkadot-primitives", - "prioritized-metered-channel", - "sc-cli", - "sc-service", - "sc-tracing", - "substrate-prometheus-endpoint", - "tracing-gum", -] - -[[package]] -name = "polkadot-node-network-protocol" -version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "async-channel", - "async-trait", - "bitvec", - "derive_more", - "fatality", - "futures", - "hex", - "parity-scale-codec", - "polkadot-node-jaeger", - "polkadot-node-primitives", - "polkadot-primitives", - "rand 0.8.5", - "sc-authority-discovery", - "sc-network", - "strum 0.24.1", - "thiserror", - "tracing-gum", -] - -[[package]] -name = "polkadot-node-primitives" -version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "bounded-vec", - "futures", - "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-primitives", - "schnorrkel", - "serde", - "sp-application-crypto", - "sp-consensus-babe", - "sp-core", - "sp-keystore", - "sp-maybe-compressed-blob", - "sp-runtime", - "thiserror", - "zstd 0.12.4", -] - -[[package]] -name = "polkadot-node-subsystem-types" -version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "async-trait", - "derive_more", - "futures", - "orchestra", - "polkadot-node-jaeger", - "polkadot-node-network-protocol", - "polkadot-node-primitives", - "polkadot-primitives", - "polkadot-statement-table", - "sc-network", - "sc-transaction-pool-api", - "smallvec", - "sp-api", - "sp-authority-discovery", - "sp-consensus-babe", - "substrate-prometheus-endpoint", - "thiserror", -] - -[[package]] -name = "polkadot-overseer" -version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "async-trait", - "futures", - "futures-timer", - "orchestra", - "parking_lot 0.12.1", - "polkadot-node-metrics", - "polkadot-node-network-protocol", - "polkadot-node-primitives", - "polkadot-node-subsystem-types", - "polkadot-primitives", - "sc-client-api", - "schnellru", - "sp-api", - "sp-core", - "tikv-jemalloc-ctl", - "tracing-gum", -] - [[package]] name = "polkadot-parachain-primitives" version = "1.0.0" @@ -6612,16 +6243,6 @@ dependencies = [ "staging-xcm-executor", ] -[[package]] -name = "polkadot-statement-table" -version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "parity-scale-codec", - "polkadot-primitives", - "sp-core", -] - [[package]] name = "polling" version = "2.8.0" @@ -6754,22 +6375,6 @@ dependencies = [ "uint", ] -[[package]] -name = "prioritized-metered-channel" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382698e48a268c832d0b181ed438374a6bb708a82a8ca273bb0f61c74cf209c4" -dependencies = [ - "coarsetime", - "crossbeam-queue", - "derive_more", - "futures", - "futures-timer", - "nanorand", - "thiserror", - "tracing", -] - [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -7616,34 +7221,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "sc-authority-discovery" -version = "0.10.0-dev" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "async-trait", - "futures", - "futures-timer", - "ip_network", - "libp2p", - "log", - "multihash", - "parity-scale-codec", - "prost", - "prost-build", - "rand 0.8.5", - "sc-client-api", - "sc-network", - "sp-api", - "sp-authority-discovery", - "sp-blockchain", - "sp-core", - "sp-keystore", - "sp-runtime", - "substrate-prometheus-endpoint", - "thiserror", -] - [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" @@ -9049,7 +8626,7 @@ source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polk dependencies = [ "Inflector", "blake2", - "expander 2.0.0", + "expander", "proc-macro-crate", "proc-macro2", "quote", @@ -10219,7 +9796,6 @@ name = "sygma-xcm-bridge" version = "0.3.0" dependencies = [ "cumulus-pallet-dmp-queue", - "cumulus-pallet-parachain-system", "cumulus-pallet-xcm", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", @@ -10388,30 +9964,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "thrift" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b82ca8f46f95b3ce96081fe3dd89160fdea970c254bb72925255d1b62aae692e" -dependencies = [ - "byteorder", - "integer-encoding", - "log", - "ordered-float", - "threadpool", -] - -[[package]] -name = "tikv-jemalloc-ctl" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619bfed27d807b54f7f776b9430d4f8060e66ee138a28632ca898584d462c31c" -dependencies = [ - "libc", - "paste", - "tikv-jemalloc-sys", -] - [[package]] name = "tikv-jemalloc-sys" version = "0.5.4+5.3.0-patched" @@ -10709,30 +10261,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tracing-gum" -version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "coarsetime", - "polkadot-node-jaeger", - "polkadot-primitives", - "tracing", - "tracing-gum-proc-macro", -] - -[[package]] -name = "tracing-gum-proc-macro" -version = "1.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.1.0#c8d2251cafadc108ba2f1f8a3208dc547ff38901" -dependencies = [ - "expander 2.0.0", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "tracing-log" version = "0.1.4" diff --git a/xcm-bridge/Cargo.toml b/xcm-bridge/Cargo.toml index 7387b292..f5fdf4b6 100644 --- a/xcm-bridge/Cargo.toml +++ b/xcm-bridge/Cargo.toml @@ -55,7 +55,6 @@ pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = # Cumulus cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } -cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index ed32d91c..d5ddbb9c 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -31,8 +31,6 @@ pub mod pallet { pub trait Config: frame_system::Config { type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type PalletIndex: Get; - type Weigher: WeightBounds; type XcmExecutor: ExecuteXcm; @@ -147,7 +145,9 @@ pub mod pallet { } } - impl Bridge for Pallet { + pub struct BridgeImpl(PhantomData); + + impl Bridge for BridgeImpl { fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult { @@ -197,7 +197,7 @@ pub mod pallet { MultiLocation::parent(), MultiLocation::new(0, dest.interior().clone()), )), - // local and children parachain have been filterred out in the TransactAsset + // local and children parachain have been filtered out in the TransactAsset _ => None, } } @@ -321,21 +321,24 @@ pub mod pallet { #[cfg(test)] mod test { use frame_support::assert_ok; + use xcm_simulator::TestExt; + use crate::Event as SygmaXcmBridgeEvent; use crate::mock::{ ALICE, BOB, ENDOWED_BALANCE, - ParaA, ParaAssets, ParaB, ParaBalances, TestNet, UsdtLocation + ParaA, ParaAssets, ParaB, ParaBalances, TestNet, }; - use crate::mock::para::Runtime; + use crate::mock::para::{assert_events, Runtime, RuntimeEvent, UsdtAssetId, UsdtLocation}; + + use super::*; #[test] fn test_transfer_self_reserve_asset_to_parachain() { TestNet::reset(); ParaA::execute_with(|| { - let bridge = Bridge::::new(); // transfer parachain A native asset from Alice to parachain B on Bob - assert_ok!(bridge.transfer(ALICE.into(), + assert_ok!(BridgeImpl::::transfer(ALICE.into(), (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), MultiLocation::new( 1, @@ -349,10 +352,28 @@ pub mod pallet { ) )); assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10); + + assert_events(vec![RuntimeEvent::SygmaXcmBridge(SygmaXcmBridgeEvent::XCMTransferSend { + asset: (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), + origin: Junction::AccountId32 { + network: None, + id: ALICE.into(), + }.into(), + dest: MultiLocation::new( + 1, + X2( + Parachain(2u32.into()), + Junction::AccountId32 { + network: None, + id: BOB.into(), + }, + ), + ), + })]); }); ParaB::execute_with(|| { - assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 10); + assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 0); }); } @@ -368,8 +389,7 @@ pub mod pallet { // Prepare step // sending parachainB native asset to parachainA ParaB::execute_with(|| { - let bridge = Bridge::::new(); - assert_ok!(bridge.transfer( + assert_ok!(BridgeImpl::::transfer( ALICE.into(), (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), MultiLocation::new( @@ -385,6 +405,24 @@ pub mod pallet { )); assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10); + + assert_events(vec![RuntimeEvent::SygmaXcmBridge(SygmaXcmBridgeEvent::XCMTransferSend { + asset: (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), + origin: Junction::AccountId32 { + network: None, + id: ALICE.into(), + }.into(), + dest: MultiLocation::new( + 1, + X2( + Parachain(1u32.into()), + Junction::AccountId32 { + network: None, + id: BOB.into(), + }, + ), + ), + })]); }); // Bob on parachainA should have parachainB's native asset ParaA::execute_with(|| { @@ -393,8 +431,7 @@ pub mod pallet { // sending parachainB's native asset from parachainA back to parachainB ParaA::execute_with(|| { - let bridge = Bridge::::new(); - assert_ok!(bridge.transfer( + assert_ok!(BridgeImpl::::transfer( BOB.into(), (Concrete(para_a_location.clone()), Fungible(5u128)).into(), // sending 5 tokens MultiLocation::new( @@ -410,6 +447,24 @@ pub mod pallet { )); assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 10 - 5); + + assert_events(vec![RuntimeEvent::SygmaXcmBridge(SygmaXcmBridgeEvent::XCMTransferSend { + asset: (Concrete(para_a_location.clone()), Fungible(5u128)).into(), + origin: Junction::AccountId32 { + network: None, + id: BOB.into(), + }.into(), + dest: MultiLocation::new( + 1, + X2( + Parachain(2u32.into()), + Junction::AccountId32 { + network: None, + id: ALICE.into(), + }, + ), + ), + })]); }); ParaA::execute_with(|| { assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10 + 5); @@ -422,8 +477,7 @@ pub mod pallet { // send USDT token from parachainA to parachainB ParaA::execute_with(|| { - let bridge = Bridge::::new(); - assert_ok!(bridge.transfer(ALICE.into(), + assert_ok!(BridgeImpl::::transfer(ALICE.into(), (Concrete(UsdtLocation::get().into()), Fungible(10u128)).into(), MultiLocation::new( 1, @@ -436,13 +490,30 @@ pub mod pallet { ), ) )); - assert_eq!(ParaAssets::balance(&ALICE), ENDOWED_BALANCE - 10); + assert_eq!(ParaAssets::balance(UsdtAssetId::get().into(), &ALICE), ENDOWED_BALANCE - 10); + + assert_events(vec![RuntimeEvent::SygmaXcmBridge(SygmaXcmBridgeEvent::XCMTransferSend { + asset: (Concrete(UsdtLocation::get().into()), Fungible(10u128)).into(), + origin: Junction::AccountId32 { + network: None, + id: ALICE.into(), + }.into(), + dest: MultiLocation::new( + 1, + X2( + Parachain(2u32.into()), + Junction::AccountId32 { + network: None, + id: BOB.into(), + }, + ), + ), + })]); }); ParaB::execute_with(|| { - assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 10); + assert_eq!(ParaAssets::balance(UsdtAssetId::get().into(), &BOB), 10); }); - } } } diff --git a/xcm-bridge/src/mock/mod.rs b/xcm-bridge/src/mock/mod.rs index 4197d1f8..39e814d9 100644 --- a/xcm-bridge/src/mock/mod.rs +++ b/xcm-bridge/src/mock/mod.rs @@ -3,313 +3,18 @@ #![cfg(test)] -use std::marker::PhantomData; -use std::result; - -use frame_support::{construct_runtime, pallet_prelude::ConstU32, parameter_types, sp_runtime::{ +use frame_support::sp_runtime::{ AccountId32, - BuildStorage, - Perbill, testing::H256, traits::{BlakeTwo256, IdentityLookup}, -}, traits::{AsEnsureOriginWithArg, ConstU128, Everything, Nothing}}; -use frame_system::{EnsureSigned, self as system}; -use polkadot_parachain_primitives::primitives::Sibling; + BuildStorage}; use sp_io::TestExternalities; -use xcm::latest::{prelude::*, Weight as XCMWeight}; -use xcm_builder::{AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit}; -use xcm_executor::{Config, traits::{Error as ExecutionError, MatchesFungibles, WithOriginFilter}, XcmExecutor}; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; -use crate as sygma_xcm_bridge; - pub mod relay; pub mod para; -type Block = frame_system::mocking::MockBlock; - -pub(crate) type Balance = u128; - -pub type AccountId = AccountId32; - -construct_runtime!( - pub enum Runtime { - System: frame_system::{Pallet, Call, Storage, Config, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Event}, - Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, - CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, - SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Event}, - SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Event}, - } -); - -parameter_types! { - pub const BlockHashCount: u64 = 250; - pub const MaximumBlockLength: u32 = 2 * 1024; - pub const AvailableBlockRatio: Perbill = Perbill::one(); - pub const MaxLocks: u32 = 100; - pub const MinimumPeriod: u64 = 1; -} - -parameter_types! { - pub const XcmBridgePalletIndex: u8 = 6; - pub RegisteredExtrinsics: Vec<(u8, Vec)> = [ - (XcmBridgePalletIndex::get(), b"transfer".to_vec()), - ].to_vec(); -} - -impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type Block = Block; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId32; - type Lookup = IdentityLookup; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<2>; -} - -parameter_types! { - pub const ExistentialDeposit: Balance = 1; -} - -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type FreezeIdentifier = (); - type MaxFreezes = (); - type RuntimeHoldReason = (); - type MaxHolds = (); -} - -parameter_types! { - pub const AssetDeposit: Balance = 1; // 1 Unit deposit to create asset - pub const ApprovalDeposit: Balance = 1; - pub const AssetsStringLimit: u32 = 50; - pub const MetadataDepositBase: Balance = 1; - pub const MetadataDepositPerByte: Balance = 1; -} - -pub type AssetId = u32; - -impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type AssetId = AssetId; - type AssetIdParameter = codec::Compact; - type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = AssetDeposit; - type AssetAccountDeposit = ConstU128<10>; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = AssetsStringLimit; - type RemoveItemsLimit = ConstU32<1000>; - type Freezer = (); - type Extra = (); - type CallbackHandle = (); - type WeightInfo = pallet_assets::weights::SubstrateWeight; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); -} - -impl sygma_xcm_bridge::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type PalletIndex = XcmBridgePalletIndex; - - type Weigher = FixedWeightBounds; - type XcmExecutor = XcmExecutor; - type SelfLocation = SelfLocation; -} - -impl sygma_bridge_forwarder::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SygmaBridge = (); - type XCMBridge = (); -} - -impl pallet_parachain_info::Config for Runtime {} - -pub struct XcmConfig; - -impl Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - type AssetTransactor = (CurrencyTransactor, FungiblesTransactor); - type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = NativeAsset; - type IsTeleporter = (); - type UniversalLocation = SelfLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = DynamicWeightTrader< - WeightPerSecond, - ::AssetId, - AssetsRegistry, - helper::XTransferTakeRevenue, - >; - type ResponseHandler = (); - type AssetTrap = (); - type AssetClaims = (); - type SubscriptionService = (); - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = ConstU32<64>; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = Everything; - type Aliasers = (); -} - -// TODO: add xcm simulator -pub type XcmRouter = ParachainXcmRouter; - -pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom, - AllowUnpaidExecutionFrom, -); - -pub type LocationToAccountId = ( - ParentIsPreset, - SiblingParachainConvertsVia, - AccountId32Aliases, -); - -pub type XcmOriginToTransactDispatchOrigin = ( - SovereignSignedViaLocation, - RelayChainAsNative, - SiblingParachainAsNative, - SignedAccountId32AsNative, -); - -parameter_types! { - pub const RelayNetwork: NetworkId = NetworkId::Rococo; - pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); - pub UnitWeightCost: XCMWeight = 1u64.into(); - pub const MaxInstructions: u32 = 100; -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; -} - -parameter_types! { - pub NativeLocation: MultiLocation = MultiLocation::here(); - pub UsdtAssetId: AssetId = 0; - pub UsdtLocation: MultiLocation = MultiLocation::new( - 1, - X3( - Parachain(2005), - slice_to_generalkey(b"sygma"), - slice_to_generalkey(b"usdt"), - ), - ); - pub CheckingAccount: AccountId32 = AccountId32::new([102u8; 32]); -} - -pub struct SimpleForeignAssetConverter(PhantomData<()>); - -impl MatchesFungibles for SimpleForeignAssetConverter { - fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), ExecutionError> { - match (&a.fun, &a.id) { - (Fungible(ref amount), Concrete(ref id)) => { - if id == &UsdtLocation::get() { - Ok((UsdtAssetId::get(), *amount)) - } else { - Err(ExecutionError::AssetNotHandled) - } - } - _ => Err(ExecutionError::AssetNotHandled), - } - } -} - -pub type CurrencyTransactor = CurrencyAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // Convert an XCM MultiLocation into a local account id: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId32, - // We don't track any teleports of `Balances`. - (), ->; - -/// Means for transacting assets besides the native currency on this chain. -pub type FungiblesTransactor = FungiblesAdapter< - // Use this fungibles implementation: - Assets, - // Use this currency when it is a fungible asset matching the given location or name: - SimpleForeignAssetConverter, - // Convert an XCM MultiLocation into a local account id: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId32, - // Disable teleport. - NoChecking, - // The account to use for tracking teleports. - CheckingAccount, ->; - -parameter_types! { - pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))); -} - -pub fn new_test_ext() -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext -} - -// Checks events against the latest. A contiguous set of events must be provided. They must -// include the most recent event, but do not have to include every past event. -pub fn assert_events(mut expected: Vec) { - let mut actual: Vec = - system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); - - expected.reverse(); - - for evt in expected { - let next = actual.pop().expect("event expected"); - assert_eq!(next, evt, "Events don't match"); - } -} - pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); pub const ENDOWED_BALANCE: u128 = 100_000_000; -pub const TEST_THRESHOLD: u32 = 2; pub type ParaBalances = pallet_balances::Pallet; pub type ParaAssets = pallet_assets::Pallet; @@ -406,16 +111,3 @@ pub fn relay_ext() -> sp_io::TestExternalities { ext.execute_with(|| System::set_block_number(1)); ext } - -pub fn slice_to_generalkey(key: &[u8]) -> Junction { - let len = key.len(); - assert!(len <= 32); - GeneralKey { - length: len as u8, - data: { - let mut data = [0u8; 32]; - data[..len].copy_from_slice(key); - data - }, - } -} \ No newline at end of file diff --git a/xcm-bridge/src/mock/para.rs b/xcm-bridge/src/mock/para.rs index 710f4ab5..66aa75d0 100644 --- a/xcm-bridge/src/mock/para.rs +++ b/xcm-bridge/src/mock/para.rs @@ -1,18 +1,29 @@ // The Licensed Work is (c) 2022 Sygma // SPDX-License-Identifier: LGPL-3.0-only -use cumulus_primitives_core::{ChannelStatus, GetChannelInfo, ParaId}; +use std::marker::PhantomData; +use std::result; + +use cumulus_primitives_core::{ChannelStatus, GetChannelInfo, ParaId, Weight}; use frame_support::{ construct_runtime, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything} + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything}, }; -use frame_support::traits::ConstU64; +use frame_support::traits::{ConstU64, Nothing}; +use frame_system as system; use frame_system::EnsureRoot; +use polkadot_parachain_primitives::primitives::Sibling; use sp_core::{crypto::AccountId32, H256}; -use sp_runtime::traits::IdentityLookup; -use xcm::latest::prelude::*; -use xcm_executor::XcmExecutor; -use crate::mock::{XcmConfig, XcmOriginToTransactDispatchOrigin}; +use sp_runtime::traits::{IdentityLookup, Zero}; +use xcm::latest::{InteriorMultiLocation, Junction, MultiAsset, MultiLocation, NetworkId, Weight as XCMWeight, XcmContext}; +use xcm::prelude::{Concrete, Fungible, GeneralKey, Parachain, X1, X3, XcmError}; +use xcm_builder::{AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit}; +use xcm_executor::{Assets as XcmAssets, Config, traits::{Error as ExecutionError, MatchesFungibles, WeightTrader, WithOriginFilter}, XcmExecutor}; + +use crate as sygma_xcm_bridge; +use crate::BridgeImpl; + +use super::ParachainXcmRouter; construct_runtime!( pub struct Runtime { @@ -20,11 +31,14 @@ construct_runtime!( Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, Assets: pallet_assets::{Pallet, Call, Storage, Event}, - ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Storage, Config}, + ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event}, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event}, + + SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Event}, + SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Event}, } ); @@ -34,6 +48,8 @@ pub(crate) type Balance = u128; pub type AccountId = AccountId32; +pub type AssetId = u32; + impl frame_system::Config for Runtime { type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; @@ -56,7 +72,7 @@ impl frame_system::Config for Runtime { type BaseCallFilter = Everything; type SystemWeightInfo = (); type SS58Prefix = (); - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + type OnSetCode = (); type MaxConsumers = ConstU32<16>; } @@ -107,8 +123,139 @@ impl pallet_assets::Config for Runtime { type BenchmarkHelper = (); } +impl sygma_xcm_bridge::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Weigher = FixedWeightBounds; + type XcmExecutor = XcmExecutor; + type SelfLocation = SelfLocation; +} + +impl sygma_bridge_forwarder::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SygmaBridge = BridgeImpl; + type XCMBridge = BridgeImpl; +} + impl pallet_parachain_info::Config for Runtime {} +pub struct XcmConfig; + +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = (CurrencyTransactor, FungiblesTransactor); + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = NativeAsset; + type IsTeleporter = (); + type UniversalLocation = SelfLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = AllTokensAreCreatedEqualToWeight; + type ResponseHandler = (); + type AssetTrap = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = ConstU32<64>; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = WithOriginFilter; + type SafeCallFilter = Everything; + type Aliasers = (); +} + +pub type XcmRouter = ParachainXcmRouter; + +pub type Barrier = ( + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + AllowUnpaidExecutionFrom, +); + +pub type LocationToAccountId = ( + ParentIsPreset, + SiblingParachainConvertsVia, + AccountId32Aliases, +); + +pub type XcmOriginToTransactDispatchOrigin = ( + SovereignSignedViaLocation, + RelayChainAsNative, + SiblingParachainAsNative, + SignedAccountId32AsNative, +); + +parameter_types! { + pub const RelayNetwork: NetworkId = NetworkId::Rococo; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UnitWeightCost: XCMWeight = 1u64.into(); + pub const MaxInstructions: u32 = 100; +} + +parameter_types! { + pub NativeLocation: MultiLocation = MultiLocation::here(); + pub UsdtAssetId: AssetId = 1; + pub UsdtLocation: MultiLocation = MultiLocation::new( + 1, + X3( + Parachain(2005), + slice_to_generalkey(b"sygma"), + slice_to_generalkey(b"usdt"), + ), + ); + pub CheckingAccount: AccountId32 = AccountId32::new([102u8; 32]); +} + +pub struct SimpleForeignAssetConverter(PhantomData<()>); + +impl MatchesFungibles for SimpleForeignAssetConverter { + fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), ExecutionError> { + match (&a.fun, &a.id) { + (Fungible(ref amount), Concrete(ref id)) => { + if id == &UsdtLocation::get() { + Ok((UsdtAssetId::get(), *amount)) + } else { + Err(ExecutionError::AssetNotHandled) + } + } + _ => Err(ExecutionError::AssetNotHandled), + } + } +} + +pub type CurrencyTransactor = CurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId32, + // We don't track any teleports of `Balances`. + (), +>; + +/// Means for transacting assets besides the native currency on this chain. +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + SimpleForeignAssetConverter, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId32, + // Disable teleport. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; + + pub struct ChannelInfo; impl GetChannelInfo for ChannelInfo { @@ -128,8 +275,8 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime { type ExecuteOverweightOrigin = EnsureRoot; type ControllerOrigin = EnsureRoot; type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type WeightInfo = (); type PriceForSiblingDelivery = (); + type WeightInfo = (); } impl cumulus_pallet_xcm::Config for Runtime { @@ -142,3 +289,74 @@ impl cumulus_pallet_dmp_queue::Config for Runtime { type XcmExecutor = XcmExecutor; type ExecuteOverweightOrigin = EnsureRoot; } + +pub struct AllTokensAreCreatedEqualToWeight(MultiLocation); + +impl WeightTrader for AllTokensAreCreatedEqualToWeight { + fn new() -> Self { + Self(MultiLocation::parent()) + } + + fn buy_weight(&mut self, weight: Weight, payment: XcmAssets, _context: &XcmContext) -> Result { + let asset_id = payment + .fungible + .iter() + .next() + .expect("Payment must be something; qed") + .0; + let required = MultiAsset { + id: asset_id.clone(), + fun: Fungible(weight.ref_time() as u128), + }; + + if let MultiAsset { + fun: _, + id: Concrete(ref id), + } = &required + { + self.0 = id.clone(); + } + + let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?; + Ok(unused) + } + + fn refund_weight(&mut self, weight: Weight, _context: &XcmContext) -> Option { + if weight.is_zero() { + None + } else { + Some((self.0.clone(), weight.ref_time() as u128).into()) + } + } +} + +parameter_types! { + pub SelfLocation: InteriorMultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))).interior; +} + +// Checks events against the latest. A contiguous set of events must be provided. They must +// include the most recent event, but do not have to include every past event. +pub fn assert_events(mut expected: Vec) { + let mut actual: Vec = + system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + + expected.reverse(); + + for evt in expected { + let next = actual.pop().expect("event expected"); + assert_eq!(next, evt, "Events don't match"); + } +} + +pub fn slice_to_generalkey(key: &[u8]) -> Junction { + let len = key.len(); + assert!(len <= 32); + GeneralKey { + length: len as u8, + data: { + let mut data = [0u8; 32]; + data[..len].copy_from_slice(key); + data + }, + } +} \ No newline at end of file diff --git a/xcm-bridge/src/mock/relay.rs b/xcm-bridge/src/mock/relay.rs index 4a624936..56e03537 100644 --- a/xcm-bridge/src/mock/relay.rs +++ b/xcm-bridge/src/mock/relay.rs @@ -125,7 +125,7 @@ pub type Barrier = (TakeWeightCredit, AllowTopLevelPaidExecutionFrom parameter_types! { pub Rococo: MultiAssetFilter = Wild(AllOf { fun: WildFungible, id: Concrete(RooLocation::get()) }); pub Statemine: MultiLocation = Parachain(3).into(); - pub KusamaForStatemine: (MultiAssetFilter, MultiLocation) = (Kusama::get(), Statemine::get()); + pub KusamaForStatemine: (MultiAssetFilter, MultiLocation) = (Rococo::get(), Statemine::get()); } parameter_types! { From 5446b0587607749351676517bc1d330ab4e720b5 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Thu, 18 Jan 2024 16:35:47 -0500 Subject: [PATCH 23/30] refacot the forwarder --- Cargo.lock | 1 + bridge-forwarder/Cargo.toml | 4 +++ bridge-forwarder/src/lib.rs | 27 +++++++++++++- .../src/xcm_asset_transactor.rs | 1 - bridge/Cargo.toml | 2 +- bridge/src/lib.rs | 24 +------------ bridge/src/mock.rs | 10 ++---- xcm-bridge/src/lib.rs | 36 ++++++++++++++----- xcm-bridge/src/mock/mod.rs | 11 +++--- xcm-bridge/src/mock/para.rs | 32 ++++++++++------- xcm-bridge/src/mock/relay.rs | 8 ++--- 11 files changed, 92 insertions(+), 64 deletions(-) rename {bridge => bridge-forwarder}/src/xcm_asset_transactor.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index fb7261c4..f5775e11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9697,6 +9697,7 @@ dependencies = [ "cumulus-primitives-utility", "frame-support", "frame-system", + "hex-literal 0.3.4", "pallet-assets", "pallet-balances", "parity-scale-codec", diff --git a/bridge-forwarder/Cargo.toml b/bridge-forwarder/Cargo.toml index 9625e767..f40c7ea3 100644 --- a/bridge-forwarder/Cargo.toml +++ b/bridge-forwarder/Cargo.toml @@ -7,11 +7,13 @@ license = "LGPL-3.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive", "serde", "decode"] } +hex-literal = { version = "0.3", default-features = false } # Substrate frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } # Polkadot xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } @@ -35,6 +37,7 @@ frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +# Local sygma-traits = { path = "../traits" } [features] @@ -45,6 +48,7 @@ std = [ "frame-support/std", "frame-system/std", "sp-std/std", + "sp-io/std", "xcm/std", "xcm-builder/std", "xcm-executor/std", diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index 8b57c693..f07e2ead 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -5,13 +5,17 @@ pub use self::pallet::*; +pub mod xcm_asset_transactor; + #[frame_support::pallet] pub mod pallet { + use cumulus_primitives_core::ParaId; use frame_support::pallet_prelude::*; use frame_support::traits::StorageVersion; use xcm::latest::{MultiAsset, MultiLocation, Junction}; + use xcm::prelude::{Concrete, Fungible, Parachain, X1}; - use sygma_traits::{Bridge, TransactorForwarder}; + use sygma_traits::{AssetTypeIdentifier, Bridge, TransactorForwarder}; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -76,4 +80,25 @@ pub mod pallet { Ok(()) } } + + pub struct NativeAssetTypeIdentifier(PhantomData); + impl> AssetTypeIdentifier for NativeAssetTypeIdentifier { + /// check if the given MultiAsset is a native asset + fn is_native_asset(asset: &MultiAsset) -> bool { + // currently there are two multilocations are considered as native asset: + // 1. integrated parachain native asset(MultiLocation::here()) + // 2. other parachain native asset(MultiLocation::new(1, X1(Parachain(T::get().into())))) + let native_locations = [ + MultiLocation::here(), + MultiLocation::new(1, X1(Parachain(T::get().into()))), + ]; + + match (&asset.id, &asset.fun) { + (Concrete(ref id), Fungible(_)) => { + native_locations.contains(id) + } + _ => false, + } + } + } } diff --git a/bridge/src/xcm_asset_transactor.rs b/bridge-forwarder/src/xcm_asset_transactor.rs similarity index 99% rename from bridge/src/xcm_asset_transactor.rs rename to bridge-forwarder/src/xcm_asset_transactor.rs index 36964e7f..34a2529d 100644 --- a/bridge/src/xcm_asset_transactor.rs +++ b/bridge-forwarder/src/xcm_asset_transactor.rs @@ -8,7 +8,6 @@ use hex_literal::hex; use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; pub struct XCMAssetTransactor(PhantomData<(CurrencyTransactor, FungiblesTransactor, AssetTypeChecker, Forwarder)>); - impl TransactAsset for XCMAssetTransactor { // deposit_asset implements the TransactAsset deposit_asset method and contains the logic to classify // the asset recipient location: diff --git a/bridge/Cargo.toml b/bridge/Cargo.toml index 28d1319c..7d56e3dc 100644 --- a/bridge/Cargo.toml +++ b/bridge/Cargo.toml @@ -67,9 +67,9 @@ xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-s xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0"} - parachains-common = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +# Local sygma-basic-feehandler = { path = "../basic-fee-handler" } sygma-traits = { path = "../traits" } diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index 099da98a..c49379fa 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -20,14 +20,12 @@ mod encode; #[cfg(test)] mod mock; -mod xcm_asset_transactor; #[allow(unused_variables)] #[allow(clippy::large_enum_variant)] #[frame_support::pallet] pub mod pallet { use codec::{Decode, Encode}; - use cumulus_primitives_core::ParaId; use ethabi::{encode as abi_encode, token::Token}; use frame_support::{ dispatch::DispatchResult, @@ -49,7 +47,7 @@ pub mod pallet { use xcm::latest::{MultiLocation, prelude::*}; use xcm_executor::traits::TransactAsset; - use sygma_traits::{AssetTypeIdentifier, Bridge, ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, MpcAddress, ResourceId, TransferType, VerifyingContractAddress}; + use sygma_traits::{Bridge, ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, MpcAddress, ResourceId, TransferType, VerifyingContractAddress}; use crate::eip712; use crate::encode::{abi::encode_packed, SolidityDataType}; @@ -683,26 +681,6 @@ pub mod pallet { } } - impl> AssetTypeIdentifier for Pallet { - /// check if the given MultiAsset is a native asset - fn is_native_asset(asset: &MultiAsset) -> bool { - // currently there are two multilocations are considered as native asset: - // 1. integrated parachain native asset(MultiLocation::here()) - // 2. other parachain native asset(MultiLocation::new(1, X1(Parachain(T::get().into())))) - let native_locations = [ - MultiLocation::here(), - MultiLocation::new(1, X1(Parachain(T::get().into()))), - ]; - - match (&asset.id, &asset.fun) { - (Concrete(ref id), Fungible(_)) => { - native_locations.contains(id) - } - _ => false, - } - } - } - impl Bridge for Pallet where ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, { diff --git a/bridge/src/mock.rs b/bridge/src/mock.rs index aef7c56c..fed102cc 100644 --- a/bridge/src/mock.rs +++ b/bridge/src/mock.rs @@ -26,12 +26,8 @@ use sygma_traits::{ VerifyingContractAddress, }; use xcm::latest::{prelude::*, AssetId as XcmAssetId, MultiLocation}; -use xcm_builder::{ - AccountId32Aliases, CurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, ParentIsPreset, - SiblingParachainConvertsVia, -}; +use xcm_builder::{AccountId32Aliases, CurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, ParentIsPreset, SiblingParachainConvertsVia}; use xcm_executor::traits::{Error as ExecutionError, MatchesFungibles}; -use crate::xcm_asset_transactor::XCMAssetTransactor; type Block = frame_system::mocking::MockBlock; @@ -48,8 +44,6 @@ frame_support::construct_runtime!( SygmaBridge: sygma_bridge::{Pallet, Call, Storage, Event} = 6, SygmaPercentageFeeHandler: sygma_percentage_feehandler::{Pallet, Call, Storage, Event} = 7, SygmaFeeHandlerRouter: sygma_fee_handler_router::{Pallet, Call, Storage, Event} = 8, - SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Event} = 9, - SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Event} = 10, } ); @@ -485,7 +479,7 @@ impl sygma_bridge::Config for Runtime { type EIP712ChainID = EIP712ChainID; type DestVerifyingContractAddress = DestVerifyingContractAddress; type FeeHandler = SygmaFeeHandlerRouter; - type AssetTransactor = XCMAssetTransactor; + type AssetTransactor = AssetTransactors; type ResourcePairs = ResourcePairs; type IsReserve = ReserveChecker; type ExtractDestData = DestinationDataParser; diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index d5ddbb9c..20caa375 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -35,8 +35,13 @@ pub mod pallet { type XcmExecutor: ExecuteXcm; + type UniversalLocation: Get; + #[pallet::constant] type SelfLocation: Get; + + /// Minimum xcm execution fee paid on destination chain. + type MinXcmFee: Get>; } pub enum TransferKind { @@ -65,6 +70,7 @@ pub mod pallet { InvalidDestination, UnknownTransferType, CannotReanchor, + NoXcmMiNFeeSet, } #[derive(PartialEq, Eq, Clone, Encode, Decode)] @@ -159,9 +165,21 @@ pub mod pallet { let (dest_location, recipient) = Pallet::::extract_dest(&dest).ok_or(Error::::InvalidDestination)?; + ensure!( + T::MinXcmFee::get().iter().position(|a| a.0 == asset.id).map(|idx| { + T::MinXcmFee::get()[idx].1 + }).is_some(), + Error::::NoXcmMiNFeeSet + ); + let fee_per_asset = T::MinXcmFee::get().iter().position(|a| a.0 == asset.id).map(|idx| { + T::MinXcmFee::get()[idx].1 + }).unwrap(); + + let fee_to_dest: MultiAsset = (asset.id, fee_per_asset).into(); + let xcm = XcmObject:: { asset: asset.clone(), - fee: asset.clone(), // TODO: fee is asset? + fee: fee_to_dest, origin: origin_location.clone(), dest: dest_location, recipient, @@ -186,8 +204,6 @@ pub mod pallet { /// extract the dest_location, recipient_location pub fn extract_dest(dest: &MultiLocation) -> Option<(MultiLocation, MultiLocation)> { match (dest.parents, dest.first_interior()) { - // parents must be 1 here because only parents as 1 can be forwarded to xcm bridge logic - // parachains (1, Some(Parachain(id))) => Some(( MultiLocation::new(1, X1(Parachain(*id))), MultiLocation::new(0, dest.interior().clone().split_first().0), @@ -336,10 +352,13 @@ pub mod pallet { fn test_transfer_self_reserve_asset_to_parachain() { TestNet::reset(); + // sending native asset from parachain A to parachain B ParaA::execute_with(|| { + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE); + // transfer parachain A native asset from Alice to parachain B on Bob assert_ok!(BridgeImpl::::transfer(ALICE.into(), - (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), + (Concrete(MultiLocation::new(0, Here)), Fungible(10_000_000_000_000u128)).into(), MultiLocation::new( 1, X2( @@ -350,11 +369,11 @@ pub mod pallet { }, ), ) - )); - assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10); + )); + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10_000_000_000_000u128); assert_events(vec![RuntimeEvent::SygmaXcmBridge(SygmaXcmBridgeEvent::XCMTransferSend { - asset: (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), + asset: (Concrete(MultiLocation::new(0, Here)), Fungible(10_000_000_000_000u128)).into(), origin: Junction::AccountId32 { network: None, id: ALICE.into(), @@ -373,7 +392,8 @@ pub mod pallet { }); ParaB::execute_with(|| { - assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 0); + assert_eq!(ParaAssets::balance(1u32.into(), &ALICE), ENDOWED_BALANCE); + assert_eq!(ParaAssets::balance(1u32.into(), &BOB), 9_000_000_000_000u128); }); } diff --git a/xcm-bridge/src/mock/mod.rs b/xcm-bridge/src/mock/mod.rs index 39e814d9..6b56ce22 100644 --- a/xcm-bridge/src/mock/mod.rs +++ b/xcm-bridge/src/mock/mod.rs @@ -14,7 +14,7 @@ pub mod para; pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); -pub const ENDOWED_BALANCE: u128 = 100_000_000; +pub const ENDOWED_BALANCE: u128 = 100_000_000_000_000_000_000; pub type ParaBalances = pallet_balances::Pallet; pub type ParaAssets = pallet_assets::Pallet; @@ -72,6 +72,7 @@ pub fn para_ext(para_id: u32) -> TestExternalities { }; parachain_info_config.assimilate_storage(&mut t).unwrap(); + // set Alice and Bob with ENDOWED_BALANCE amount of native asset on every parachain pallet_balances::GenesisConfig:: { balances: vec![ (ALICE, ENDOWED_BALANCE), @@ -81,10 +82,11 @@ pub fn para_ext(para_id: u32) -> TestExternalities { .assimilate_storage(&mut t) .unwrap(); + // set Alice with ENDOWED_BALANCE amount of USDT asset on every parachain pallet_assets::GenesisConfig:: { - assets: vec![(0, ALICE, false, 1)], - metadata: vec![(0, "USDT".into(), "USDT".into(), 6)], - accounts: vec![(0, ALICE, ENDOWED_BALANCE)], + assets: vec![(1, ALICE, false, 1)], + metadata: vec![(1, "USDT".into(), "USDT".into(), 6)], + accounts: vec![(1, ALICE, ENDOWED_BALANCE)], } .assimilate_storage(&mut t) .unwrap(); @@ -101,6 +103,7 @@ pub fn relay_ext() -> sp_io::TestExternalities { .build_storage() .unwrap(); + // set Alice with ENDOWED_BALANCE amount of native asset on relay chain pallet_balances::GenesisConfig:: { balances: vec![(ALICE, ENDOWED_BALANCE)], } diff --git a/xcm-bridge/src/mock/para.rs b/xcm-bridge/src/mock/para.rs index 66aa75d0..92d6bccc 100644 --- a/xcm-bridge/src/mock/para.rs +++ b/xcm-bridge/src/mock/para.rs @@ -9,17 +9,20 @@ use frame_support::{ construct_runtime, parameter_types, traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything}, }; -use frame_support::traits::{ConstU64, Nothing}; +use frame_support::traits::{ConstU16, ConstU64, Nothing}; use frame_system as system; use frame_system::EnsureRoot; use polkadot_parachain_primitives::primitives::Sibling; use sp_core::{crypto::AccountId32, H256}; use sp_runtime::traits::{IdentityLookup, Zero}; -use xcm::latest::{InteriorMultiLocation, Junction, MultiAsset, MultiLocation, NetworkId, Weight as XCMWeight, XcmContext}; -use xcm::prelude::{Concrete, Fungible, GeneralKey, Parachain, X1, X3, XcmError}; +use xcm::latest::{AssetId as XcmAssetId, InteriorMultiLocation, Junction, MultiAsset, MultiLocation, NetworkId, Weight as XCMWeight, XcmContext}; +use xcm::prelude::{Concrete, Fungible, GeneralKey, GlobalConsensus, Parachain, X1, X2, X3, XcmError}; use xcm_builder::{AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit}; use xcm_executor::{Assets as XcmAssets, Config, traits::{Error as ExecutionError, MatchesFungibles, WeightTrader, WithOriginFilter}, XcmExecutor}; +use sygma_bridge_forwarder; +use sygma_bridge_forwarder::xcm_asset_transactor::XCMAssetTransactor; + use crate as sygma_xcm_bridge; use crate::BridgeImpl; @@ -42,6 +45,7 @@ construct_runtime!( } ); + type Block = frame_system::mocking::MockBlock; pub(crate) type Balance = u128; @@ -71,7 +75,7 @@ impl frame_system::Config for Runtime { type DbWeight = (); type BaseCallFilter = Everything; type SystemWeightInfo = (); - type SS58Prefix = (); + type SS58Prefix = ConstU16<20>; type OnSetCode = (); type MaxConsumers = ConstU32<16>; } @@ -127,7 +131,9 @@ impl sygma_xcm_bridge::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Weigher = FixedWeightBounds; type XcmExecutor = XcmExecutor; + type UniversalLocation = UniversalLocation; type SelfLocation = SelfLocation; + type MinXcmFee = MinXcmFee; } impl sygma_bridge_forwarder::Config for Runtime { @@ -139,15 +145,14 @@ impl sygma_bridge_forwarder::Config for Runtime { impl pallet_parachain_info::Config for Runtime {} pub struct XcmConfig; - impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; - type AssetTransactor = (CurrencyTransactor, FungiblesTransactor); + type AssetTransactor = XCMAssetTransactor, SygmaBridgeForwarder, >; type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = NativeAsset; type IsTeleporter = (); - type UniversalLocation = SelfLocation; + type UniversalLocation = UniversalLocation; type Barrier = Barrier; type Weigher = FixedWeightBounds; type Trader = AllTokensAreCreatedEqualToWeight; @@ -209,6 +214,13 @@ parameter_types! { pub CheckingAccount: AccountId32 = AccountId32::new([102u8; 32]); } +parameter_types! { + pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))); + pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); + + pub MinXcmFee: Vec<(XcmAssetId, u128)> = vec![(NativeLocation::get().into(), 1_000_000_000_000u128), (UsdtLocation::get().into(), 1_000_000u128)]; +} + pub struct SimpleForeignAssetConverter(PhantomData<()>); impl MatchesFungibles for SimpleForeignAssetConverter { @@ -255,7 +267,6 @@ pub type FungiblesTransactor = FungiblesAdapter< CheckingAccount, >; - pub struct ChannelInfo; impl GetChannelInfo for ChannelInfo { @@ -291,7 +302,6 @@ impl cumulus_pallet_dmp_queue::Config for Runtime { } pub struct AllTokensAreCreatedEqualToWeight(MultiLocation); - impl WeightTrader for AllTokensAreCreatedEqualToWeight { fn new() -> Self { Self(MultiLocation::parent()) @@ -330,10 +340,6 @@ impl WeightTrader for AllTokensAreCreatedEqualToWeight { } } -parameter_types! { - pub SelfLocation: InteriorMultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))).interior; -} - // Checks events against the latest. A contiguous set of events must be provided. They must // include the most recent event, but do not have to include every past event. pub fn assert_events(mut expected: Vec) { diff --git a/xcm-bridge/src/mock/relay.rs b/xcm-bridge/src/mock/relay.rs index 56e03537..81bcea87 100644 --- a/xcm-bridge/src/mock/relay.rs +++ b/xcm-bridge/src/mock/relay.rs @@ -1,7 +1,7 @@ // The Licensed Work is (c) 2022 Sygma // SPDX-License-Identifier: LGPL-3.0-only -use cumulus_primitives_core::ParaId; +use cumulus_primitives_core::ParaId; use frame_support::{ construct_runtime, parameter_types, traits::{Everything, ProcessMessage, ProcessMessageError}, @@ -101,7 +101,7 @@ impl configuration::Config for Runtime { parameter_types! { pub RooLocation: MultiLocation = Here.into(); pub const RococoNetwork: NetworkId = NetworkId::Rococo; - pub UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(RococoNetwork::get())); + pub UniversalLocation: InteriorMultiLocation = Here; } pub type SovereignAccountOf = ( @@ -130,13 +130,12 @@ parameter_types! { parameter_types! { pub const UnitWeightCost: Weight = Weight::from_parts(10, 10); - pub const BaseXcmWeight: Weight = Weight::from_parts(100_000_000, 100_000_000); + pub const BaseXcmWeight: Weight = Weight::from_parts(10, 0); pub const MaxInstructions: u32 = 100; pub const MaxAssetsIntoHolding: u32 = 64; } pub struct XcmConfig; - impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; @@ -205,7 +204,6 @@ parameter_types! { } pub struct MessageProcessor; - impl ProcessMessage for MessageProcessor { type Origin = AggregateMessageOrigin; From 18bb1cc680721ff3e51e8faff26116e86f46467b Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Fri, 19 Jan 2024 12:23:16 -0500 Subject: [PATCH 24/30] add unit test with runtime for brdige forwarder --- Cargo.lock | 1 + bridge-forwarder/Cargo.toml | 3 + bridge-forwarder/src/lib.rs | 69 ++++++++ bridge-forwarder/src/mock.rs | 173 +++++++++++++++++++ bridge-forwarder/src/xcm_asset_transactor.rs | 3 + xcm-bridge/src/lib.rs | 2 +- 6 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 bridge-forwarder/src/mock.rs diff --git a/Cargo.lock b/Cargo.lock index f5775e11..03b202b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9700,6 +9700,7 @@ dependencies = [ "hex-literal 0.3.4", "pallet-assets", "pallet-balances", + "pallet-parachain-info", "parity-scale-codec", "scale-info", "sp-io", diff --git a/bridge-forwarder/Cargo.toml b/bridge-forwarder/Cargo.toml index f40c7ea3..76592870 100644 --- a/bridge-forwarder/Cargo.toml +++ b/bridge-forwarder/Cargo.toml @@ -14,6 +14,8 @@ frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } +pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } # Polkadot xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0", default-features = false } @@ -39,6 +41,7 @@ pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch # Local sygma-traits = { path = "../traits" } +pallet-parachain-info = { path = "../parachain-info" } [features] default = ["std"] diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index f07e2ead..d7d5f505 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -6,6 +6,8 @@ pub use self::pallet::*; pub mod xcm_asset_transactor; +#[cfg(test)] +mod mock; #[frame_support::pallet] pub mod pallet { @@ -101,4 +103,71 @@ pub mod pallet { } } } + + #[cfg(test)] + mod test { + use frame_support::assert_ok; + use xcm::latest::Junction; + use xcm::prelude::{Concrete, Fungible, Parachain, X2, Here, X1}; + use xcm::v3::Junction::GeneralIndex; + use xcm::v3::{MultiAsset, MultiLocation}; + use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; + use crate::mock::{new_test_ext, SygmaBridgeForwarder, ALICE, assert_events, RuntimeEvent, ParachainInfo}; + use crate::{Event as SygmaBridgeForwarderEvent, NativeAssetTypeIdentifier}; + #[test] + fn test_xcm_transactor_forwarder() { + new_test_ext().execute_with(|| { + + let asset: MultiAsset = (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + let dest: MultiLocation = MultiLocation::new(1, X2(Parachain(1), GeneralIndex(1u128))); + + assert_ok!(SygmaBridgeForwarder::xcm_transactor_forwarder(ALICE.into(), asset.clone(), dest.clone())); + + assert_events(vec![RuntimeEvent::SygmaBridgeForwarder(SygmaBridgeForwarderEvent::XCMTransferForward { + asset, + origin: Junction::AccountId32 { + network: None, + id: ALICE.into(), + }.into(), + dest, + })]); + }) + } + + #[test] + fn test_other_world_transactor_forwarder() { + new_test_ext().execute_with(|| { + + let asset: MultiAsset = (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + let dest: MultiLocation = MultiLocation::new(1, X2(Parachain(1), GeneralIndex(1u128))); + + assert_ok!(SygmaBridgeForwarder::other_world_transactor_forwarder(ALICE.into(), asset.clone(), dest.clone())); + + assert_events(vec![RuntimeEvent::SygmaBridgeForwarder(SygmaBridgeForwarderEvent::OtherWorldTransferForward { + asset, + origin: Junction::AccountId32 { + network: None, + id: ALICE.into(), + }.into(), + dest, + })]); + }) + } + + #[test] + fn test_asset_type_identifier_native_asset() { + new_test_ext().execute_with(|| { + + let asset_local_native: MultiAsset = (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + assert_eq!(NativeAssetTypeIdentifier::::is_native_asset(&asset_local_native), true); + + // ParachainInfo is given parachain ID as 100 + let asset_foreign_native: MultiAsset = (Concrete(MultiLocation::new(1, X1(Parachain(100)))), Fungible(10u128)).into(); + assert_eq!(NativeAssetTypeIdentifier::::is_native_asset(&asset_foreign_native), true); + + let asset_foreign_asset: MultiAsset = (Concrete(MultiLocation::new(0, X1(Parachain(100)))), Fungible(10u128)).into(); + assert_eq!(NativeAssetTypeIdentifier::::is_native_asset(&asset_foreign_asset), false); + }) + } + } } diff --git a/bridge-forwarder/src/mock.rs b/bridge-forwarder/src/mock.rs new file mode 100644 index 00000000..58cacc4d --- /dev/null +++ b/bridge-forwarder/src/mock.rs @@ -0,0 +1,173 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +#![cfg(test)] + +use frame_support::construct_runtime; +use frame_support::dispatch::DispatchResult; +use frame_support::pallet_prelude::ConstU32; +use frame_support::parameter_types; +use frame_support::traits::AsEnsureOriginWithArg; +use frame_system::{self as system}; +use frame_system::EnsureSigned; +use sp_runtime::{AccountId32, BuildStorage}; +use sp_runtime::testing::H256; +use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; +use xcm::latest::{MultiAsset, MultiLocation}; + +use sygma_traits::Bridge; + +use crate as sygma_bridge_forwarder; + +construct_runtime!( + pub struct Runtime{ + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + Assets: pallet_assets::{Pallet, Call, Storage, Config, Event}, + SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Event}, + + ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, + } +); + +pub(crate) type Balance = u128; + +type Block = frame_system::mocking::MockBlock; + +parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +impl frame_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId32; + type Lookup = IdentityLookup; + type Block = Block; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<2>; +} + +parameter_types! { + pub const ExistentialDeposit: Balance = 1; +} + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); + type MaxHolds = (); +} + +parameter_types! { + pub const AssetDeposit: Balance = 0; + pub const AssetAccountDeposit: Balance =0; + pub const ApprovalDeposit: Balance = ExistentialDeposit::get(); + pub const AssetsStringLimit: u32 = 50; + /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) + // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 + pub const MetadataDepositBase: Balance = 0; + pub const MetadataDepositPerByte: Balance = 0; +} + +pub type AssetId = u32; + +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetIdParameter = codec::Compact; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = AssetAccountDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type RemoveItemsLimit = ConstU32<1000>; + type Freezer = (); + type Extra = (); + type CallbackHandle = (); + type WeightInfo = pallet_assets::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +impl sygma_bridge_forwarder::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type SygmaBridge = BridgeImplRuntime; + type XCMBridge = BridgeImplRuntime; +} + +pub struct BridgeImplRuntime; +impl Bridge for BridgeImplRuntime { + fn transfer(_sender: [u8; 32], _asset: MultiAsset, _dest: MultiLocation) -> DispatchResult { + Ok(()) + } +} + +impl pallet_parachain_info::Config for Runtime {} + +pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); +pub const ASSET_OWNER: AccountId32 = AccountId32::new([1u8; 32]); +pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); +pub const ENDOWED_BALANCE: Balance = 1_000_000_000_000_000_000_000_000_000; + +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![ + (ALICE, ENDOWED_BALANCE), + (ASSET_OWNER, ENDOWED_BALANCE), + (BOB, ENDOWED_BALANCE), + ], + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +// Checks events against the latest. A contiguous set of events must be provided. They must +// include the most recent event, but do not have to include every past event. +#[allow(dead_code)] +pub fn assert_events(mut expected: Vec) { + let mut actual: Vec = + system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + + expected.reverse(); + + for evt in expected { + let next = actual.pop().expect("event expected"); + assert_eq!(next, evt, "Events don't match"); + } +} \ No newline at end of file diff --git a/bridge-forwarder/src/xcm_asset_transactor.rs b/bridge-forwarder/src/xcm_asset_transactor.rs index 34a2529d..5da00647 100644 --- a/bridge-forwarder/src/xcm_asset_transactor.rs +++ b/bridge-forwarder/src/xcm_asset_transactor.rs @@ -1,3 +1,6 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + use core::marker::PhantomData; use codec::Encode; diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 20caa375..193e491d 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -5,6 +5,7 @@ pub use self::pallet::*; +#[cfg(test)] mod mock; #[frame_support::pallet] @@ -152,7 +153,6 @@ pub mod pallet { } pub struct BridgeImpl(PhantomData); - impl Bridge for BridgeImpl { fn transfer(sender: [u8; 32], asset: MultiAsset, From 04590447db4e7dfe5a8ad646bff72f3a1d414740 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Mon, 22 Jan 2024 16:18:59 -0500 Subject: [PATCH 25/30] unit test for bridge pallet transfer method and xcm asset transactor --- Cargo.lock | 2 + bridge-forwarder/Cargo.toml | 4 + bridge-forwarder/src/lib.rs | 378 +- bridge-forwarder/src/mock.rs | 317 +- bridge-forwarder/src/xcm_asset_transactor.rs | 95 +- bridge/src/lib.rs | 4898 +++++++++--------- bridge/src/mock.rs | 7 +- traits/src/lib.rs | 20 +- xcm-bridge/src/lib.rs | 1015 ++-- xcm-bridge/src/mock/mod.rs | 97 +- xcm-bridge/src/mock/para.rs | 455 +- xcm-bridge/src/mock/relay.rs | 266 +- 12 files changed, 3907 insertions(+), 3647 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03b202b2..0eac108f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9701,7 +9701,9 @@ dependencies = [ "pallet-assets", "pallet-balances", "pallet-parachain-info", + "pallet-timestamp", "parity-scale-codec", + "polkadot-parachain-primitives", "scale-info", "sp-io", "sp-runtime", diff --git a/bridge-forwarder/Cargo.toml b/bridge-forwarder/Cargo.toml index 76592870..fbc63cd6 100644 --- a/bridge-forwarder/Cargo.toml +++ b/bridge-forwarder/Cargo.toml @@ -38,6 +38,10 @@ frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } +pallet-timestamp = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } + +# Polkadot +polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.1.0" } # Local sygma-traits = { path = "../traits" } diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index d7d5f505..69f4a3be 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -5,169 +5,227 @@ pub use self::pallet::*; -pub mod xcm_asset_transactor; #[cfg(test)] mod mock; +pub mod xcm_asset_transactor; #[frame_support::pallet] pub mod pallet { - use cumulus_primitives_core::ParaId; - use frame_support::pallet_prelude::*; - use frame_support::traits::StorageVersion; - use xcm::latest::{MultiAsset, MultiLocation, Junction}; - use xcm::prelude::{Concrete, Fungible, Parachain, X1}; - - use sygma_traits::{AssetTypeIdentifier, Bridge, TransactorForwarder}; - - const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); - - #[pallet::pallet] - #[pallet::storage_version(STORAGE_VERSION)] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - type SygmaBridge: Bridge; - type XCMBridge: Bridge; - } - - #[pallet::event] - #[pallet::generate_deposit(pub (super) fn deposit_event)] - pub enum Event { - XCMTransferForward { - asset: MultiAsset, - origin: MultiLocation, - dest: MultiLocation, - }, - OtherWorldTransferForward { - asset: MultiAsset, - origin: MultiLocation, - dest: MultiLocation, - }, - } - - impl TransactorForwarder for Pallet { - fn xcm_transactor_forwarder(origin: [u8; 32], what: MultiAsset, dest: MultiLocation) -> DispatchResult { - T::XCMBridge::transfer(origin, what.clone(), dest.clone())?; - - let origin_location: MultiLocation = Junction::AccountId32 { - network: None, - id: origin, - }.into(); - - Pallet::::deposit_event(Event::XCMTransferForward { - asset: what, - origin: origin_location, - dest, - }); - - Ok(()) - } - - fn other_world_transactor_forwarder(origin: [u8; 32], what: MultiAsset, dest: MultiLocation) -> DispatchResult { - T::SygmaBridge::transfer(origin, what.clone(), dest.clone())?; - - let origin_location: MultiLocation = Junction::AccountId32 { - network: None, - id: origin, - }.into(); - - Pallet::::deposit_event(Event::OtherWorldTransferForward { - asset: what, - origin: origin_location, - dest, - }); - - Ok(()) - } - } - - pub struct NativeAssetTypeIdentifier(PhantomData); - impl> AssetTypeIdentifier for NativeAssetTypeIdentifier { - /// check if the given MultiAsset is a native asset - fn is_native_asset(asset: &MultiAsset) -> bool { - // currently there are two multilocations are considered as native asset: - // 1. integrated parachain native asset(MultiLocation::here()) - // 2. other parachain native asset(MultiLocation::new(1, X1(Parachain(T::get().into())))) - let native_locations = [ - MultiLocation::here(), - MultiLocation::new(1, X1(Parachain(T::get().into()))), - ]; - - match (&asset.id, &asset.fun) { - (Concrete(ref id), Fungible(_)) => { - native_locations.contains(id) - } - _ => false, - } - } - } - - #[cfg(test)] - mod test { - use frame_support::assert_ok; - use xcm::latest::Junction; - use xcm::prelude::{Concrete, Fungible, Parachain, X2, Here, X1}; - use xcm::v3::Junction::GeneralIndex; - use xcm::v3::{MultiAsset, MultiLocation}; - use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; - use crate::mock::{new_test_ext, SygmaBridgeForwarder, ALICE, assert_events, RuntimeEvent, ParachainInfo}; - use crate::{Event as SygmaBridgeForwarderEvent, NativeAssetTypeIdentifier}; - #[test] - fn test_xcm_transactor_forwarder() { - new_test_ext().execute_with(|| { - - let asset: MultiAsset = (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); - let dest: MultiLocation = MultiLocation::new(1, X2(Parachain(1), GeneralIndex(1u128))); - - assert_ok!(SygmaBridgeForwarder::xcm_transactor_forwarder(ALICE.into(), asset.clone(), dest.clone())); - - assert_events(vec![RuntimeEvent::SygmaBridgeForwarder(SygmaBridgeForwarderEvent::XCMTransferForward { - asset, - origin: Junction::AccountId32 { - network: None, - id: ALICE.into(), - }.into(), - dest, - })]); - }) - } - - #[test] - fn test_other_world_transactor_forwarder() { - new_test_ext().execute_with(|| { - - let asset: MultiAsset = (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); - let dest: MultiLocation = MultiLocation::new(1, X2(Parachain(1), GeneralIndex(1u128))); - - assert_ok!(SygmaBridgeForwarder::other_world_transactor_forwarder(ALICE.into(), asset.clone(), dest.clone())); - - assert_events(vec![RuntimeEvent::SygmaBridgeForwarder(SygmaBridgeForwarderEvent::OtherWorldTransferForward { - asset, - origin: Junction::AccountId32 { - network: None, - id: ALICE.into(), - }.into(), - dest, - })]); - }) - } - - #[test] - fn test_asset_type_identifier_native_asset() { - new_test_ext().execute_with(|| { - - let asset_local_native: MultiAsset = (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); - assert_eq!(NativeAssetTypeIdentifier::::is_native_asset(&asset_local_native), true); - - // ParachainInfo is given parachain ID as 100 - let asset_foreign_native: MultiAsset = (Concrete(MultiLocation::new(1, X1(Parachain(100)))), Fungible(10u128)).into(); - assert_eq!(NativeAssetTypeIdentifier::::is_native_asset(&asset_foreign_native), true); - - let asset_foreign_asset: MultiAsset = (Concrete(MultiLocation::new(0, X1(Parachain(100)))), Fungible(10u128)).into(); - assert_eq!(NativeAssetTypeIdentifier::::is_native_asset(&asset_foreign_asset), false); - }) - } - } + use cumulus_primitives_core::ParaId; + use frame_support::pallet_prelude::*; + use frame_support::traits::StorageVersion; + use xcm::latest::{Junction, MultiAsset, MultiLocation}; + use xcm::prelude::{Concrete, Fungible, Parachain, X1}; + + use sygma_traits::{AssetTypeIdentifier, Bridge, TransactorForwarder}; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type SygmaBridge: Bridge; + type XCMBridge: Bridge; + } + + #[pallet::event] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + XCMTransferForward { asset: MultiAsset, origin: MultiLocation, dest: MultiLocation }, + OtherWorldTransferForward { asset: MultiAsset, origin: MultiLocation, dest: MultiLocation }, + } + + impl TransactorForwarder for Pallet { + fn xcm_transactor_forwarder( + origin: [u8; 32], + what: MultiAsset, + dest: MultiLocation, + ) -> DispatchResult { + T::XCMBridge::transfer(origin, what.clone(), dest)?; + + let origin_location: MultiLocation = + Junction::AccountId32 { network: None, id: origin }.into(); + + Pallet::::deposit_event(Event::XCMTransferForward { + asset: what, + origin: origin_location, + dest, + }); + + Ok(()) + } + + fn other_world_transactor_forwarder( + origin: [u8; 32], + what: MultiAsset, + dest: MultiLocation, + ) -> DispatchResult { + T::SygmaBridge::transfer(origin, what.clone(), dest)?; + + let origin_location: MultiLocation = + Junction::AccountId32 { network: None, id: origin }.into(); + + Pallet::::deposit_event(Event::OtherWorldTransferForward { + asset: what, + origin: origin_location, + dest, + }); + + Ok(()) + } + } + + pub struct NativeAssetTypeIdentifier(PhantomData); + + impl> AssetTypeIdentifier for NativeAssetTypeIdentifier { + /// check if the given MultiAsset is a native asset + fn is_native_asset(asset: &MultiAsset) -> bool { + // currently there are two multilocations are considered as native asset: + // 1. integrated parachain native asset(MultiLocation::here()) + // 2. other parachain native asset(MultiLocation::new(1, X1(Parachain(T::get().into())))) + let native_locations = + [MultiLocation::here(), MultiLocation::new(1, X1(Parachain(T::get().into())))]; + + match (&asset.id, &asset.fun) { + (Concrete(ref id), Fungible(_)) => native_locations.contains(id), + _ => false, + } + } + } + + #[cfg(test)] + mod test { + use frame_support::assert_ok; + use xcm::latest::{Junction, XcmContext}; + use xcm::prelude::{AccountId32, Concrete, Fungible, Here, Parachain, X1, X2}; + use xcm::v3::Junction::GeneralIndex; + use xcm::v3::{MultiAsset, MultiLocation}; + use xcm_executor::traits::TransactAsset; + + use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; + + use crate::mock::{ + assert_events, new_test_ext, Assets, Balances, CurrencyTransactor, + ForwarderImplRuntime, FungiblesTransactor, ParachainInfo, RuntimeEvent, + SygmaBridgeForwarder, UsdtAssetId, UsdtLocation, ALICE, BOB, + }; + use crate::{ + xcm_asset_transactor::XCMAssetTransactor, Event as SygmaBridgeForwarderEvent, + NativeAssetTypeIdentifier, + }; + + #[test] + fn test_xcm_transactor_forwarder() { + new_test_ext().execute_with(|| { + let asset: MultiAsset = + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + let dest: MultiLocation = + MultiLocation::new(1, X2(Parachain(1), GeneralIndex(1u128))); + + assert_ok!(SygmaBridgeForwarder::xcm_transactor_forwarder( + ALICE.into(), + asset.clone(), + dest + )); + + assert_events(vec![RuntimeEvent::SygmaBridgeForwarder( + SygmaBridgeForwarderEvent::XCMTransferForward { + asset, + origin: Junction::AccountId32 { network: None, id: ALICE.into() }.into(), + dest, + }, + )]); + }) + } + + #[test] + fn test_other_world_transactor_forwarder() { + new_test_ext().execute_with(|| { + let asset: MultiAsset = + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + let dest: MultiLocation = + MultiLocation::new(1, X2(Parachain(1), GeneralIndex(1u128))); + + assert_ok!(SygmaBridgeForwarder::other_world_transactor_forwarder( + ALICE.into(), + asset.clone(), + dest + )); + + assert_events(vec![RuntimeEvent::SygmaBridgeForwarder( + SygmaBridgeForwarderEvent::OtherWorldTransferForward { + asset, + origin: Junction::AccountId32 { network: None, id: ALICE.into() }.into(), + dest, + }, + )]); + }) + } + + #[test] + fn test_asset_type_identifier_native_asset() { + new_test_ext().execute_with(|| { + let asset_local_native: MultiAsset = + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + assert!(NativeAssetTypeIdentifier::::is_native_asset( + &asset_local_native + )); + + // ParachainInfo is given parachain ID as 100 + let asset_foreign_native: MultiAsset = + (Concrete(MultiLocation::new(1, X1(Parachain(100)))), Fungible(10u128)).into(); + assert!(NativeAssetTypeIdentifier::::is_native_asset( + &asset_foreign_native + )); + + let asset_foreign_asset: MultiAsset = + (Concrete(MultiLocation::new(0, X1(Parachain(100)))), Fungible(10u128)).into(); + assert!(!NativeAssetTypeIdentifier::::is_native_asset( + &asset_foreign_asset + )); + }) + } + + #[test] + fn test_xcm_asset_transactor_local() { + new_test_ext().execute_with(|| { + let local_recipient: MultiLocation = + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })); + + // send native asset to local parachain + let local_native_asset: MultiAsset = + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + assert_ok!(XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::deposit_asset( + &local_native_asset, + &local_recipient, + &XcmContext::with_message_id([0; 32]) + )); + assert_eq!(Balances::free_balance(BOB), 10u128); + + // send foreign asset to local parachain + let local_foreign_asset: MultiAsset = + (Concrete(UsdtLocation::get()), Fungible(10u128)).into(); + assert_ok!(XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::deposit_asset( + &local_foreign_asset, + &local_recipient, + &XcmContext::with_message_id([0; 32]) + )); + assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), 10u128); + }) + } + } } diff --git a/bridge-forwarder/src/mock.rs b/bridge-forwarder/src/mock.rs index 58cacc4d..e578f2e5 100644 --- a/bridge-forwarder/src/mock.rs +++ b/bridge-forwarder/src/mock.rs @@ -3,19 +3,29 @@ #![cfg(test)] -use frame_support::construct_runtime; +use std::marker::PhantomData; +use std::result; + use frame_support::dispatch::DispatchResult; -use frame_support::pallet_prelude::ConstU32; -use frame_support::parameter_types; -use frame_support::traits::AsEnsureOriginWithArg; -use frame_system::{self as system}; +use frame_support::{ + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, ConstU32}, +}; +use frame_system as system; use frame_system::EnsureSigned; -use sp_runtime::{AccountId32, BuildStorage}; +use polkadot_parachain_primitives::primitives::Sibling; use sp_runtime::testing::H256; use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; -use xcm::latest::{MultiAsset, MultiLocation}; +use sp_runtime::{AccountId32, BuildStorage}; +use xcm::latest::{BodyId, Junction, MultiAsset, MultiLocation, NetworkId}; +use xcm::prelude::{Concrete, Fungible, GeneralKey, Parachain, X3}; +use xcm_builder::{ + AccountId32Aliases, CurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, ParentIsPreset, + SiblingParachainConvertsVia, +}; +use xcm_executor::traits::{Error as ExecutionError, MatchesFungibles}; -use sygma_traits::Bridge; +use sygma_traits::{Bridge, TransactorForwarder}; use crate as sygma_bridge_forwarder; @@ -23,45 +33,48 @@ construct_runtime!( pub struct Runtime{ System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, - Assets: pallet_assets::{Pallet, Call, Storage, Config, Event}, + Assets: pallet_assets::{Pallet, Call, Storage, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Event}, - - ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, + ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, } ); pub(crate) type Balance = u128; +pub type AccountId = AccountId32; + type Block = frame_system::mocking::MockBlock; parameter_types! { - pub const BlockHashCount: u64 = 250; + pub const BlockHashCount: u64 = 250; + pub const MinimumPeriod: u64 = 1; } impl frame_system::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = AccountId32; - type Lookup = IdentityLookup; - type Block = Block; - type BlockHashCount = BlockHashCount; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<2>; + type RuntimeEvent = RuntimeEvent; + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId32; + type Lookup = IdentityLookup; + type Block = Block; + type BlockHashCount = BlockHashCount; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<2>; } parameter_types! { @@ -69,68 +82,76 @@ parameter_types! { } impl pallet_balances::Config for Runtime { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type FreezeIdentifier = (); - type MaxFreezes = (); - type RuntimeHoldReason = (); - type MaxHolds = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type RuntimeHoldReason = (); + type MaxHolds = ConstU32<1>; + type MaxFreezes = ConstU32<1>; } parameter_types! { pub const AssetDeposit: Balance = 0; - pub const AssetAccountDeposit: Balance =0; + pub const AssetAccountDeposit: Balance = 0; pub const ApprovalDeposit: Balance = ExistentialDeposit::get(); pub const AssetsStringLimit: u32 = 50; /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) // https://github.com/paritytech/substrate/blob/069917b/frame/assets/src/lib.rs#L257L271 pub const MetadataDepositBase: Balance = 0; pub const MetadataDepositPerByte: Balance = 0; + pub const ExecutiveBody: BodyId = BodyId::Executive; } pub type AssetId = u32; impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type AssetId = AssetId; - type AssetIdParameter = codec::Compact; - type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = AssetDeposit; - type AssetAccountDeposit = AssetAccountDeposit; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = AssetsStringLimit; - type RemoveItemsLimit = ConstU32<1000>; - type Freezer = (); - type Extra = (); - type CallbackHandle = (); - type WeightInfo = pallet_assets::weights::SubstrateWeight; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = AssetId; + type AssetIdParameter = codec::Compact; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = AssetDeposit; + type AssetAccountDeposit = AssetAccountDeposit; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type RemoveItemsLimit = ConstU32<1000>; + type Freezer = (); + type Extra = (); + type CallbackHandle = (); + type WeightInfo = pallet_assets::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +impl pallet_timestamp::Config for Runtime { + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); } impl sygma_bridge_forwarder::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SygmaBridge = BridgeImplRuntime; - type XCMBridge = BridgeImplRuntime; + type RuntimeEvent = RuntimeEvent; + type SygmaBridge = BridgeImplRuntime; + type XCMBridge = BridgeImplRuntime; } -pub struct BridgeImplRuntime; -impl Bridge for BridgeImplRuntime { - fn transfer(_sender: [u8; 32], _asset: MultiAsset, _dest: MultiLocation) -> DispatchResult { - Ok(()) - } +pub struct BridgeImplRuntime(PhantomData); +impl Bridge for BridgeImplRuntime { + fn transfer(_sender: [u8; 32], _asset: MultiAsset, _dest: MultiLocation) -> DispatchResult { + Ok(()) + } } impl pallet_parachain_info::Config for Runtime {} @@ -141,33 +162,127 @@ pub const BOB: AccountId32 = AccountId32::new([2u8; 32]); pub const ENDOWED_BALANCE: Balance = 1_000_000_000_000_000_000_000_000_000; pub fn new_test_ext() -> sp_io::TestExternalities { - let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); - - pallet_balances::GenesisConfig:: { - balances: vec![ - (ALICE, ENDOWED_BALANCE), - (ASSET_OWNER, ENDOWED_BALANCE), - (BOB, ENDOWED_BALANCE), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(ALICE, ENDOWED_BALANCE), (ASSET_OWNER, ENDOWED_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext } -// Checks events against the latest. A contiguous set of events must be provided. They must -// include the most recent event, but do not have to include every past event. #[allow(dead_code)] pub fn assert_events(mut expected: Vec) { - let mut actual: Vec = - system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + let mut actual: Vec = + system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + + expected.reverse(); + + for evt in expected { + let next = actual.pop().expect("event expected"); + assert_eq!(next, evt, "Events don't match"); + } +} + +// mock the generic types of XCMAssetTransactor +parameter_types! { + pub NativeLocation: MultiLocation = MultiLocation::here(); + pub UsdtAssetId: AssetId = 1; + pub UsdtLocation: MultiLocation = MultiLocation::new( + 1, + X3( + Parachain(2005), + slice_to_generalkey(b"sygma"), + slice_to_generalkey(b"usdt"), + ), + ); + pub CheckingAccount: AccountId32 = AccountId32::new([102u8; 32]); - expected.reverse(); + pub const RelayNetwork: NetworkId = NetworkId::Rococo; +} + +pub type CurrencyTransactor = CurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId32, + // We don't track any teleports of `Balances`. + (), +>; + +pub type FungiblesTransactor = FungiblesAdapter< + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + SimpleForeignAssetConverter, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId32, + // Disable teleport. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; + +pub type LocationToAccountId = ( + ParentIsPreset, + SiblingParachainConvertsVia, + AccountId32Aliases, +); + +pub struct SimpleForeignAssetConverter(PhantomData<()>); +impl MatchesFungibles for SimpleForeignAssetConverter { + fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), ExecutionError> { + match (&a.fun, &a.id) { + (Fungible(ref amount), Concrete(ref id)) => { + if id == &UsdtLocation::get() { + Ok((UsdtAssetId::get(), *amount)) + } else { + Err(ExecutionError::AssetNotHandled) + } + }, + _ => Err(ExecutionError::AssetNotHandled), + } + } +} - for evt in expected { - let next = actual.pop().expect("event expected"); - assert_eq!(next, evt, "Events don't match"); - } -} \ No newline at end of file +pub fn slice_to_generalkey(key: &[u8]) -> Junction { + let len = key.len(); + assert!(len <= 32); + GeneralKey { + length: len as u8, + data: { + let mut data = [0u8; 32]; + data[..len].copy_from_slice(key); + data + }, + } +} + +pub struct ForwarderImplRuntime; + +impl TransactorForwarder for ForwarderImplRuntime { + fn xcm_transactor_forwarder( + _sender: [u8; 32], + _what: MultiAsset, + _dest: MultiLocation, + ) -> DispatchResult { + Ok(()) + } + + fn other_world_transactor_forwarder( + _sender: [u8; 32], + _what: MultiAsset, + _dest: MultiLocation, + ) -> DispatchResult { + Ok(()) + } +} diff --git a/bridge-forwarder/src/xcm_asset_transactor.rs b/bridge-forwarder/src/xcm_asset_transactor.rs index 5da00647..fc3050fb 100644 --- a/bridge-forwarder/src/xcm_asset_transactor.rs +++ b/bridge-forwarder/src/xcm_asset_transactor.rs @@ -4,34 +4,43 @@ use core::marker::PhantomData; use codec::Encode; -use xcm::latest::{Junction, MultiAsset, MultiLocation, XcmContext}; -use xcm::prelude::*; -use xcm_executor::{Assets, traits::TransactAsset}; use hex_literal::hex; use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; +use xcm::latest::{Junction, MultiAsset, MultiLocation, XcmContext}; +use xcm::prelude::*; +use xcm_executor::{traits::TransactAsset, Assets}; -pub struct XCMAssetTransactor(PhantomData<(CurrencyTransactor, FungiblesTransactor, AssetTypeChecker, Forwarder)>); -impl TransactAsset for XCMAssetTransactor { - // deposit_asset implements the TransactAsset deposit_asset method and contains the logic to classify - // the asset recipient location: - // 1. recipient is on the local parachain - // 2. recipient is on non-substrate chain(evm, cosmos, etc.) - // 3. recipient is on the remote parachain - fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { - match (who.parents, who.first_interior()) { - // 1. recipient is on the local parachain - (0, Some(Parachain(_))) => { - // check if the asset is native, and call the corresponding deposit_asset() - if AssetTypeChecker::is_native_asset(what) { - CurrencyTransactor::deposit_asset(what, who, context)?; - } else { - FungiblesTransactor::deposit_asset(what, who, context)? - } - } - // recipient is on the remote chain - (1, Some(Parachain(_))) => { - // 2. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet - match who.interior { +pub struct XCMAssetTransactor( + PhantomData<(CurrencyTransactor, FungiblesTransactor, AssetTypeChecker, Forwarder)>, +); +impl< + CurrencyTransactor: TransactAsset, + FungiblesTransactor: TransactAsset, + AssetTypeChecker: AssetTypeIdentifier, + Forwarder: TransactorForwarder, + > TransactAsset + for XCMAssetTransactor +{ + // deposit_asset implements the TransactAsset deposit_asset method and contains the logic to classify + // the asset recipient location: + // 1. recipient is on the local parachain + // 2. recipient is on non-substrate chain(evm, cosmos, etc.) + // 3. recipient is on the remote parachain + fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { + match (who.parents, who.first_interior()) { + // 1. recipient is on the local parachain + (0, Some(AccountId32 { .. })) => { + // check if the asset is native, and call the corresponding deposit_asset() + if AssetTypeChecker::is_native_asset(what) { + CurrencyTransactor::deposit_asset(what, who, context)?; + } else { + FungiblesTransactor::deposit_asset(what, who, context)? + } + }, + // recipient is on the remote chain + (1, Some(Parachain(_))) => { + // 2. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet + match who.interior { // sygma: 7379676d61000000000000000000000000000000000000000000000000000000 // sygma-bridge: 7379676d612d6272696467650000000000000000000000000000000000000000 X5(Parachain(1000), GeneralKey { length: 5, data: hex!["7379676d61000000000000000000000000000000000000000000000000000000"]}, GeneralKey { length: 12, data: hex!["7379676d612d6272696467650000000000000000000000000000000000000000"]}, GeneralIndex(..), GeneralKey { .. }) => { @@ -61,23 +70,27 @@ impl { - return Err(XcmError::DestinationUnsupported); - } - } + }, + // Other destination multiLocation not supported, return Err + _ => { + return Err(XcmError::DestinationUnsupported); + }, + } - Ok(()) - } + Ok(()) + } - fn withdraw_asset(what: &MultiAsset, who: &MultiLocation, maybe_context: Option<&XcmContext>) -> Result { - let assets = if AssetTypeChecker::is_native_asset(what) { - CurrencyTransactor::withdraw_asset(what, who, maybe_context)? - } else { - FungiblesTransactor::withdraw_asset(what, who, maybe_context)? - }; + fn withdraw_asset( + what: &MultiAsset, + who: &MultiLocation, + maybe_context: Option<&XcmContext>, + ) -> Result { + let assets = if AssetTypeChecker::is_native_asset(what) { + CurrencyTransactor::withdraw_asset(what, who, maybe_context)? + } else { + FungiblesTransactor::withdraw_asset(what, who, maybe_context)? + }; - Ok(assets) - } + Ok(assets) + } } diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index c49379fa..ca28706d 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -25,267 +25,270 @@ mod mock; #[allow(clippy::large_enum_variant)] #[frame_support::pallet] pub mod pallet { - use codec::{Decode, Encode}; - use ethabi::{encode as abi_encode, token::Token}; - use frame_support::{ - dispatch::DispatchResult, - pallet_prelude::*, - PalletId, - traits::{ContainsPair, StorageVersion}, transactional, - }; - use frame_support::dispatch::RawOrigin; - use frame_system::pallet_prelude::*; - use primitive_types::U256; - use scale_info::TypeInfo; - use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; - use sp_runtime::{ - RuntimeDebug, - traits::{AccountIdConversion, Clear}, - }; - use sp_std::{boxed::Box, convert::From, vec, vec::Vec}; - use sp_std::collections::btree_map::BTreeMap; - use xcm::latest::{MultiLocation, prelude::*}; - use xcm_executor::traits::TransactAsset; - - use sygma_traits::{Bridge, ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, MpcAddress, ResourceId, TransferType, VerifyingContractAddress}; - - use crate::eip712; - use crate::encode::{abi::encode_packed, SolidityDataType}; - - #[allow(dead_code)] - const LOG_TARGET: &str = "runtime::sygmabridge"; - const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); - - #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] - pub struct Proposal { - pub origin_domain_id: DomainID, - pub deposit_nonce: DepositNonce, - pub resource_id: ResourceId, - pub data: Vec, - } - - pub trait WeightInfo { - fn pause_bridge() -> Weight; - fn unpause_bridge() -> Weight; - fn set_mpc_address() -> Weight; - fn register_domain() -> Weight; - fn unregister_domain() -> Weight; - fn deposit() -> Weight; - fn retry() -> Weight; - fn execute_proposal(n: u32) -> Weight; - fn pause_all_bridges() -> Weight; - fn unpause_all_bridges() -> Weight; - } - - #[pallet::pallet] - #[pallet::storage_version(STORAGE_VERSION)] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config + sygma_access_segregator::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - /// Bridge transfer reserve accounts mapping with designated assets - #[pallet::constant] - type TransferReserveAccounts: Get>; - - /// EIP712 Verifying contract address - /// This is used in EIP712 typed data domain - #[pallet::constant] - type DestVerifyingContractAddress: Get; - - /// Pallet ChainID - /// This is used in EIP712 typed data domain - #[pallet::constant] - type EIP712ChainID: Get; - - /// Fee reserve account - #[pallet::constant] - type FeeReserveAccount: Get; - - /// Fee information getter - type FeeHandler: FeeHandler; - - /// Implementation of withdraw and deposit an asset. - type AssetTransactor: TransactAsset; - - /// AssetId and ResourceId pairs - type ResourcePairs: Get>; - - /// Return true if asset reserved on current chain - type IsReserve: ContainsPair; - - /// Extract dest data from given MultiLocation - type ExtractDestData: ExtractDestinationData; - - /// Config ID for the current pallet instance - type PalletId: Get; - - /// Current pallet index defined in runtime - type PalletIndex: Get; - - /// Asset decimal converter - type DecimalConverter: DecimalConverter; - - /// Type representing the weight of this pallet - type WeightInfo: WeightInfo; - } - - #[allow(dead_code)] - #[pallet::event] - #[pallet::generate_deposit(pub (super) fn deposit_event)] - pub enum Event { - /// When initial bridge transfer send to dest domain - /// args: [dest_domain_id, resource_id, deposit_nonce, sender, transfer_type, - /// deposit_data, handler_response, ] - Deposit { - dest_domain_id: DomainID, - resource_id: ResourceId, - deposit_nonce: DepositNonce, - sender: T::AccountId, - transfer_type: TransferType, - deposit_data: Vec, - handler_response: Vec, - }, - /// When proposal was executed successfully - ProposalExecution { - origin_domain_id: DomainID, - deposit_nonce: DepositNonce, - data_hash: [u8; 32], - }, - /// When proposal was faild to execute - FailedHandlerExecution { - error: Vec, - origin_domain_id: DomainID, - deposit_nonce: DepositNonce, - }, - /// When user is going to retry a bridge transfer - /// args: [deposit_on_block_height, dest_domain_id, sender] - Retry { deposit_on_block_height: u128, dest_domain_id: DomainID, sender: T::AccountId }, - /// When bridge is paused - /// args: [dest_domain_id] - BridgePaused { dest_domain_id: DomainID }, - /// When bridge is unpaused - /// args: [dest_domain_id] - BridgeUnpaused { dest_domain_id: DomainID }, - /// When registering a new dest domainID with its corresponding chainID - RegisterDestDomain { sender: T::AccountId, domain_id: DomainID, chain_id: ChainID }, - /// When unregistering a dest domainID with its corresponding chainID - UnregisterDestDomain { sender: T::AccountId, domain_id: DomainID, chain_id: ChainID }, - /// When bridge fee is collected - FeeCollected { - fee_payer: T::AccountId, - dest_domain_id: DomainID, - resource_id: ResourceId, - fee_amount: u128, - fee_asset_id: AssetId, - }, - /// When all bridges are paused - AllBridgePaused { sender: T::AccountId }, - /// When all bridges are unpaused - AllBridgeUnpaused { sender: T::AccountId }, - } - - #[pallet::error] - pub enum Error { - /// Account has not gained access permission - AccessDenied, - /// Protected operation, must be performed by relayer - BadMpcSignature, - /// Insufficient balance on sender account - InsufficientBalance, - /// Asset transactor execution failed - TransactFailed, - /// The withdrawn amount can not cover the fee payment - FeeTooExpensive, - /// MPC address not set - MissingMpcAddress, - /// MPC address can not be updated - MpcAddrNotUpdatable, - /// Bridge is paused - BridgePaused, - /// Bridge is unpaused - BridgeUnpaused, - /// Fee config option missing - MissingFeeConfig, - /// Asset not bound to a resource id - AssetNotBound, - /// Proposal has either failed or succeeded - ProposalAlreadyComplete, - /// Proposal list empty - EmptyProposalList, - /// Transactor operation failed - TransactorFailed, - /// Deposit data not correct - InvalidDepositData, - /// Dest domain not supported - DestDomainNotSupported, - /// Dest chain id not match - DestChainIDNotMatch, - /// Failed to extract destination data - ExtractDestDataFailed, - /// Failed on the decimal converter - DecimalConversionFail, - /// Deposit nonce has reached max integer value - DepositNonceOverflow, - /// Asset not bound to a liquidity holder account - NoLiquidityHolderAccountBound, - /// Function unimplemented - Unimplemented, - } - - /// Deposit counter of dest domain - #[pallet::storage] - #[pallet::getter(fn deposit_counts)] - pub type DepositCounts = StorageMap<_, Twox64Concat, DomainID, DepositNonce, ValueQuery>; - - /// Bridge Pause indicator - /// Bridge is unpaused initially, until pause - /// After mpc address setup, bridge should be paused until ready to unpause - #[pallet::storage] - #[pallet::getter(fn is_paused)] - pub type IsPaused = StorageMap<_, Twox64Concat, DomainID, bool, ValueQuery>; - - /// Pre-set MPC address - #[pallet::storage] - #[pallet::getter(fn mpc_addr)] - pub type MpcAddr = StorageValue<_, MpcAddress, ValueQuery>; - - /// Mark whether a deposit nonce was used. Used to mark execution status of a proposal. - #[pallet::storage] - #[pallet::getter(fn used_nonces)] - pub type UsedNonces = StorageDoubleMap< - _, - Twox64Concat, - DomainID, - Twox64Concat, - DepositNonce, - DepositNonce, - ValueQuery, - >; - - /// Mark supported dest domainID - #[pallet::storage] - #[pallet::getter(fn dest_domain_ids)] - pub type DestDomainIds = StorageMap<_, Twox64Concat, DomainID, bool, ValueQuery>; - - /// Mark the pairs for supported dest domainID with its corresponding chainID - /// The chainID is not directly used in pallet, this map is designed more about rechecking the - /// domainID - #[pallet::storage] - #[pallet::getter(fn dest_chain_ids)] - pub type DestChainIds = StorageMap<_, Twox64Concat, DomainID, ChainID>; - - #[pallet::call] - impl Pallet - where - ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, - { - /// Pause bridge, this would lead to bridge transfer failure before it being unpaused. - #[pallet::call_index(0)] - #[pallet::weight(< T as Config >::WeightInfo::pause_bridge())] - pub fn pause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { - ensure!( + use codec::{Decode, Encode}; + use ethabi::{encode as abi_encode, token::Token}; + use frame_support::dispatch::RawOrigin; + use frame_support::{ + dispatch::DispatchResult, + pallet_prelude::*, + traits::{ContainsPair, StorageVersion}, + transactional, PalletId, + }; + use frame_system::pallet_prelude::*; + use primitive_types::U256; + use scale_info::TypeInfo; + use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; + use sp_runtime::{ + traits::{AccountIdConversion, Clear}, + RuntimeDebug, + }; + use sp_std::collections::btree_map::BTreeMap; + use sp_std::{boxed::Box, convert::From, vec, vec::Vec}; + use xcm::latest::{prelude::*, MultiLocation}; + use xcm_executor::traits::TransactAsset; + + use sygma_traits::{ + Bridge, ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, + FeeHandler, MpcAddress, ResourceId, TransferType, VerifyingContractAddress, + }; + + use crate::eip712; + use crate::encode::{abi::encode_packed, SolidityDataType}; + + #[allow(dead_code)] + const LOG_TARGET: &str = "runtime::sygmabridge"; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + + #[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] + pub struct Proposal { + pub origin_domain_id: DomainID, + pub deposit_nonce: DepositNonce, + pub resource_id: ResourceId, + pub data: Vec, + } + + pub trait WeightInfo { + fn pause_bridge() -> Weight; + fn unpause_bridge() -> Weight; + fn set_mpc_address() -> Weight; + fn register_domain() -> Weight; + fn unregister_domain() -> Weight; + fn deposit() -> Weight; + fn retry() -> Weight; + fn execute_proposal(n: u32) -> Weight; + fn pause_all_bridges() -> Weight; + fn unpause_all_bridges() -> Weight; + } + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config + sygma_access_segregator::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Bridge transfer reserve accounts mapping with designated assets + #[pallet::constant] + type TransferReserveAccounts: Get>; + + /// EIP712 Verifying contract address + /// This is used in EIP712 typed data domain + #[pallet::constant] + type DestVerifyingContractAddress: Get; + + /// Pallet ChainID + /// This is used in EIP712 typed data domain + #[pallet::constant] + type EIP712ChainID: Get; + + /// Fee reserve account + #[pallet::constant] + type FeeReserveAccount: Get; + + /// Fee information getter + type FeeHandler: FeeHandler; + + /// Implementation of withdraw and deposit an asset. + type AssetTransactor: TransactAsset; + + /// AssetId and ResourceId pairs + type ResourcePairs: Get>; + + /// Return true if asset reserved on current chain + type IsReserve: ContainsPair; + + /// Extract dest data from given MultiLocation + type ExtractDestData: ExtractDestinationData; + + /// Config ID for the current pallet instance + type PalletId: Get; + + /// Current pallet index defined in runtime + type PalletIndex: Get; + + /// Asset decimal converter + type DecimalConverter: DecimalConverter; + + /// Type representing the weight of this pallet + type WeightInfo: WeightInfo; + } + + #[allow(dead_code)] + #[pallet::event] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + /// When initial bridge transfer send to dest domain + /// args: [dest_domain_id, resource_id, deposit_nonce, sender, transfer_type, + /// deposit_data, handler_response, ] + Deposit { + dest_domain_id: DomainID, + resource_id: ResourceId, + deposit_nonce: DepositNonce, + sender: T::AccountId, + transfer_type: TransferType, + deposit_data: Vec, + handler_response: Vec, + }, + /// When proposal was executed successfully + ProposalExecution { + origin_domain_id: DomainID, + deposit_nonce: DepositNonce, + data_hash: [u8; 32], + }, + /// When proposal was faild to execute + FailedHandlerExecution { + error: Vec, + origin_domain_id: DomainID, + deposit_nonce: DepositNonce, + }, + /// When user is going to retry a bridge transfer + /// args: [deposit_on_block_height, dest_domain_id, sender] + Retry { deposit_on_block_height: u128, dest_domain_id: DomainID, sender: T::AccountId }, + /// When bridge is paused + /// args: [dest_domain_id] + BridgePaused { dest_domain_id: DomainID }, + /// When bridge is unpaused + /// args: [dest_domain_id] + BridgeUnpaused { dest_domain_id: DomainID }, + /// When registering a new dest domainID with its corresponding chainID + RegisterDestDomain { sender: T::AccountId, domain_id: DomainID, chain_id: ChainID }, + /// When unregistering a dest domainID with its corresponding chainID + UnregisterDestDomain { sender: T::AccountId, domain_id: DomainID, chain_id: ChainID }, + /// When bridge fee is collected + FeeCollected { + fee_payer: T::AccountId, + dest_domain_id: DomainID, + resource_id: ResourceId, + fee_amount: u128, + fee_asset_id: AssetId, + }, + /// When all bridges are paused + AllBridgePaused { sender: T::AccountId }, + /// When all bridges are unpaused + AllBridgeUnpaused { sender: T::AccountId }, + } + + #[pallet::error] + pub enum Error { + /// Account has not gained access permission + AccessDenied, + /// Protected operation, must be performed by relayer + BadMpcSignature, + /// Insufficient balance on sender account + InsufficientBalance, + /// Asset transactor execution failed + TransactFailed, + /// The withdrawn amount can not cover the fee payment + FeeTooExpensive, + /// MPC address not set + MissingMpcAddress, + /// MPC address can not be updated + MpcAddrNotUpdatable, + /// Bridge is paused + BridgePaused, + /// Bridge is unpaused + BridgeUnpaused, + /// Fee config option missing + MissingFeeConfig, + /// Asset not bound to a resource id + AssetNotBound, + /// Proposal has either failed or succeeded + ProposalAlreadyComplete, + /// Proposal list empty + EmptyProposalList, + /// Transactor operation failed + TransactorFailed, + /// Deposit data not correct + InvalidDepositData, + /// Dest domain not supported + DestDomainNotSupported, + /// Dest chain id not match + DestChainIDNotMatch, + /// Failed to extract destination data + ExtractDestDataFailed, + /// Failed on the decimal converter + DecimalConversionFail, + /// Deposit nonce has reached max integer value + DepositNonceOverflow, + /// Asset not bound to a liquidity holder account + NoLiquidityHolderAccountBound, + /// Function unimplemented + Unimplemented, + } + + /// Deposit counter of dest domain + #[pallet::storage] + #[pallet::getter(fn deposit_counts)] + pub type DepositCounts = StorageMap<_, Twox64Concat, DomainID, DepositNonce, ValueQuery>; + + /// Bridge Pause indicator + /// Bridge is unpaused initially, until pause + /// After mpc address setup, bridge should be paused until ready to unpause + #[pallet::storage] + #[pallet::getter(fn is_paused)] + pub type IsPaused = StorageMap<_, Twox64Concat, DomainID, bool, ValueQuery>; + + /// Pre-set MPC address + #[pallet::storage] + #[pallet::getter(fn mpc_addr)] + pub type MpcAddr = StorageValue<_, MpcAddress, ValueQuery>; + + /// Mark whether a deposit nonce was used. Used to mark execution status of a proposal. + #[pallet::storage] + #[pallet::getter(fn used_nonces)] + pub type UsedNonces = StorageDoubleMap< + _, + Twox64Concat, + DomainID, + Twox64Concat, + DepositNonce, + DepositNonce, + ValueQuery, + >; + + /// Mark supported dest domainID + #[pallet::storage] + #[pallet::getter(fn dest_domain_ids)] + pub type DestDomainIds = StorageMap<_, Twox64Concat, DomainID, bool, ValueQuery>; + + /// Mark the pairs for supported dest domainID with its corresponding chainID + /// The chainID is not directly used in pallet, this map is designed more about rechecking the + /// domainID + #[pallet::storage] + #[pallet::getter(fn dest_chain_ids)] + pub type DestChainIds = StorageMap<_, Twox64Concat, DomainID, ChainID>; + + #[pallet::call] + impl Pallet + where + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, + { + /// Pause bridge, this would lead to bridge transfer failure before it being unpaused. + #[pallet::call_index(0)] + #[pallet::weight(< T as Config >::WeightInfo::pause_bridge())] + pub fn pause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"pause_bridge".to_vec(), @@ -293,21 +296,21 @@ pub mod pallet { ), Error::::AccessDenied ); - ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); + ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); - // Mark as paused - IsPaused::::insert(dest_domain_id, true); + // Mark as paused + IsPaused::::insert(dest_domain_id, true); - // Emit BridgePause event - Self::deposit_event(Event::BridgePaused { dest_domain_id }); - Ok(()) - } + // Emit BridgePause event + Self::deposit_event(Event::BridgePaused { dest_domain_id }); + Ok(()) + } - /// Unpause bridge. - #[pallet::call_index(1)] - #[pallet::weight(< T as Config >::WeightInfo::unpause_bridge())] - pub fn unpause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { - ensure!( + /// Unpause bridge. + #[pallet::call_index(1)] + #[pallet::weight(< T as Config >::WeightInfo::unpause_bridge())] + pub fn unpause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"unpause_bridge".to_vec(), @@ -315,24 +318,24 @@ pub mod pallet { ), Error::::AccessDenied ); - ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); + ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); - // make sure the current status is paused - ensure!(IsPaused::::get(dest_domain_id), Error::::BridgeUnpaused); + // make sure the current status is paused + ensure!(IsPaused::::get(dest_domain_id), Error::::BridgeUnpaused); - // Mark as unpaused - IsPaused::::insert(dest_domain_id, false); + // Mark as unpaused + IsPaused::::insert(dest_domain_id, false); - // Emit BridgeUnpause event - Self::deposit_event(Event::BridgeUnpaused { dest_domain_id }); - Ok(()) - } + // Emit BridgeUnpause event + Self::deposit_event(Event::BridgeUnpaused { dest_domain_id }); + Ok(()) + } - /// Mark an ECDSA address as a MPC account. - #[pallet::call_index(2)] - #[pallet::weight(< T as Config >::WeightInfo::set_mpc_address())] - pub fn set_mpc_address(origin: OriginFor, addr: MpcAddress) -> DispatchResult { - ensure!( + /// Mark an ECDSA address as a MPC account. + #[pallet::call_index(2)] + #[pallet::weight(< T as Config >::WeightInfo::set_mpc_address())] + pub fn set_mpc_address(origin: OriginFor, addr: MpcAddress) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"set_mpc_address".to_vec(), @@ -340,27 +343,27 @@ pub mod pallet { ), Error::::AccessDenied ); - // Cannot set MPC address as it's already set - ensure!(MpcAddr::::get().is_clear(), Error::::MpcAddrNotUpdatable); - - // Set MPC account address - MpcAddr::::set(addr); - - // unpause bridge - Self::unpause_all_domains(); - - Ok(()) - } - - /// Mark the give dest domainID with chainID to be enabled - #[pallet::call_index(3)] - #[pallet::weight(< T as Config >::WeightInfo::register_domain())] - pub fn register_domain( - origin: OriginFor, - dest_domain_id: DomainID, - dest_chain_id: ChainID, - ) -> DispatchResult { - ensure!( + // Cannot set MPC address as it's already set + ensure!(MpcAddr::::get().is_clear(), Error::::MpcAddrNotUpdatable); + + // Set MPC account address + MpcAddr::::set(addr); + + // unpause bridge + Self::unpause_all_domains(); + + Ok(()) + } + + /// Mark the give dest domainID with chainID to be enabled + #[pallet::call_index(3)] + #[pallet::weight(< T as Config >::WeightInfo::register_domain())] + pub fn register_domain( + origin: OriginFor, + dest_domain_id: DomainID, + dest_chain_id: ChainID, + ) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"register_domain".to_vec(), @@ -369,31 +372,31 @@ pub mod pallet { Error::::AccessDenied ); - DestDomainIds::::insert(dest_domain_id, true); - DestChainIds::::insert(dest_domain_id, dest_chain_id); - - // Emit register dest domain event - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::RegisterDestDomain { - sender, - domain_id: dest_domain_id, - chain_id: dest_chain_id, - }); - Ok(()) - } - - /// Mark the give dest domainID with chainID to be disabled - #[pallet::call_index(4)] - #[pallet::weight(< T as Config >::WeightInfo::unregister_domain())] - pub fn unregister_domain( - origin: OriginFor, - dest_domain_id: DomainID, - dest_chain_id: ChainID, - ) -> DispatchResult { - ensure!( + DestDomainIds::::insert(dest_domain_id, true); + DestChainIds::::insert(dest_domain_id, dest_chain_id); + + // Emit register dest domain event + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::RegisterDestDomain { + sender, + domain_id: dest_domain_id, + chain_id: dest_chain_id, + }); + Ok(()) + } + + /// Mark the give dest domainID with chainID to be disabled + #[pallet::call_index(4)] + #[pallet::weight(< T as Config >::WeightInfo::unregister_domain())] + pub fn unregister_domain( + origin: OriginFor, + dest_domain_id: DomainID, + dest_chain_id: ChainID, + ) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"unregister_domain".to_vec(), @@ -401,143 +404,143 @@ pub mod pallet { ), Error::::AccessDenied ); - ensure!( + ensure!( DestDomainIds::::get(dest_domain_id) && DestChainIds::::get(dest_domain_id).is_some(), Error::::DestDomainNotSupported ); - let co_chain_id = DestChainIds::::get(dest_domain_id).unwrap(); - ensure!(co_chain_id == dest_chain_id, Error::::DestChainIDNotMatch); - - DestDomainIds::::remove(dest_domain_id); - DestChainIds::::remove(dest_domain_id); - - // Emit unregister dest domain event - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::UnregisterDestDomain { - sender, - domain_id: dest_domain_id, - chain_id: dest_chain_id, - }); - Ok(()) - } - - /// Initiates a transfer. - #[transactional] - #[pallet::call_index(5)] - #[pallet::weight(< T as Config >::WeightInfo::deposit())] - pub fn deposit( - origin: OriginFor, - asset: Box, - dest: Box, - ) -> DispatchResult { - let sender = ensure_signed(origin)?; - - ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); - - // Extract dest (MultiLocation) to get corresponding dest domainID and Ethereum - // recipient address - let (recipient, dest_domain_id) = - T::ExtractDestData::extract_dest(&dest).ok_or(Error::::ExtractDestDataFailed)?; - - ensure!(!IsPaused::::get(dest_domain_id), Error::::BridgePaused); - - ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); - - // Extract asset (MultiAsset) to get corresponding ResourceId, transfer amount and the - // transfer type - let (resource_id, amount, transfer_type) = - Self::extract_asset(&asset.clone()).ok_or(Error::::AssetNotBound)?; - // Return error if no fee handler set - let fee = T::FeeHandler::get_fee(dest_domain_id, *asset.clone()) - .ok_or(Error::::MissingFeeConfig)?; - - ensure!(amount > fee, Error::::FeeTooExpensive); - - // Withdraw `amount` of asset from sender - T::AssetTransactor::withdraw_asset( - &asset, - &Junction::AccountId32 { network: None, id: sender.clone().into() }.into(), - None, - ) - .map_err(|_| Error::::TransactFailed)?; - - // Deposit `fee` of asset to treasury account - T::AssetTransactor::deposit_asset( - &(asset.id, Fungible(fee)).into(), - &Junction::AccountId32 { network: None, id: T::FeeReserveAccount::get().into() } - .into(), - // Put empty message hash here because we are not sending XCM message - &XcmContext::with_message_id([0; 32]), - ) - .map_err(|_| Error::::TransactFailed)?; - - let bridge_amount = amount - fee; - - let token_reserved_account = Self::get_token_reserved_account(&asset.id) - .ok_or(Error::::NoLiquidityHolderAccountBound)?; - - // Deposit `bridge_amount` of asset to reserve account if asset is reserved in local - // chain. - if T::IsReserve::contains(&asset, &MultiLocation::here()) { - T::AssetTransactor::deposit_asset( - &(asset.id, Fungible(bridge_amount)).into(), - &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), - // Put empty message hash here because we are not sending XCM message - &XcmContext::with_message_id([0; 32]), - ) - .map_err(|_| Error::::TransactFailed)?; - } - - // Bump deposit nonce - let deposit_nonce = DepositCounts::::get(dest_domain_id); - DepositCounts::::insert( - dest_domain_id, - deposit_nonce.checked_add(1).ok_or(Error::::DepositNonceOverflow)?, - ); + let co_chain_id = DestChainIds::::get(dest_domain_id).unwrap(); + ensure!(co_chain_id == dest_chain_id, Error::::DestChainIDNotMatch); + + DestDomainIds::::remove(dest_domain_id); + DestChainIds::::remove(dest_domain_id); + + // Emit unregister dest domain event + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::UnregisterDestDomain { + sender, + domain_id: dest_domain_id, + chain_id: dest_chain_id, + }); + Ok(()) + } + + /// Initiates a transfer. + #[transactional] + #[pallet::call_index(5)] + #[pallet::weight(< T as Config >::WeightInfo::deposit())] + pub fn deposit( + origin: OriginFor, + asset: Box, + dest: Box, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); + + // Extract dest (MultiLocation) to get corresponding dest domainID and Ethereum + // recipient address + let (recipient, dest_domain_id) = + T::ExtractDestData::extract_dest(&dest).ok_or(Error::::ExtractDestDataFailed)?; + + ensure!(!IsPaused::::get(dest_domain_id), Error::::BridgePaused); + + ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); + + // Extract asset (MultiAsset) to get corresponding ResourceId, transfer amount and the + // transfer type + let (resource_id, amount, transfer_type) = + Self::extract_asset(&asset.clone()).ok_or(Error::::AssetNotBound)?; + // Return error if no fee handler set + let fee = T::FeeHandler::get_fee(dest_domain_id, *asset.clone()) + .ok_or(Error::::MissingFeeConfig)?; + + ensure!(amount > fee, Error::::FeeTooExpensive); + + // Withdraw `amount` of asset from sender + T::AssetTransactor::withdraw_asset( + &asset, + &Junction::AccountId32 { network: None, id: sender.clone().into() }.into(), + None, + ) + .map_err(|_| Error::::TransactFailed)?; + + // Deposit `fee` of asset to treasury account + T::AssetTransactor::deposit_asset( + &(asset.id, Fungible(fee)).into(), + &Junction::AccountId32 { network: None, id: T::FeeReserveAccount::get().into() } + .into(), + // Put empty message hash here because we are not sending XCM message + &XcmContext::with_message_id([0; 32]), + ) + .map_err(|_| Error::::TransactFailed)?; + + let bridge_amount = amount - fee; + + let token_reserved_account = Self::get_token_reserved_account(&asset.id) + .ok_or(Error::::NoLiquidityHolderAccountBound)?; + + // Deposit `bridge_amount` of asset to reserve account if asset is reserved in local + // chain. + if T::IsReserve::contains(&asset, &MultiLocation::here()) { + T::AssetTransactor::deposit_asset( + &(asset.id, Fungible(bridge_amount)).into(), + &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), + // Put empty message hash here because we are not sending XCM message + &XcmContext::with_message_id([0; 32]), + ) + .map_err(|_| Error::::TransactFailed)?; + } + + // Bump deposit nonce + let deposit_nonce = DepositCounts::::get(dest_domain_id); + DepositCounts::::insert( + dest_domain_id, + deposit_nonce.checked_add(1).ok_or(Error::::DepositNonceOverflow)?, + ); - // convert the asset decimal - let decimal_converted_amount = - T::DecimalConverter::convert_to(&(asset.id, bridge_amount).into()) - .ok_or(Error::::DecimalConversionFail)?; - - // Emit Deposit event - Self::deposit_event(Event::Deposit { - dest_domain_id, - resource_id, - deposit_nonce, - sender: sender.clone(), - transfer_type, - deposit_data: Self::create_deposit_data(decimal_converted_amount, recipient), - handler_response: vec![], - }); - - // Emit FeeCollected event - Self::deposit_event(Event::FeeCollected { - fee_payer: sender, - dest_domain_id, - resource_id, - fee_amount: fee, - fee_asset_id: asset.id, - }); - - Ok(()) - } - - /// This method is used to trigger the process for retrying failed deposits on the MPC side. - #[transactional] - #[pallet::call_index(6)] - #[pallet::weight(< T as Config >::WeightInfo::retry())] - pub fn retry( - origin: OriginFor, - deposit_on_block_height: u128, - dest_domain_id: DomainID, - ) -> DispatchResult { - ensure!( + // convert the asset decimal + let decimal_converted_amount = + T::DecimalConverter::convert_to(&(asset.id, bridge_amount).into()) + .ok_or(Error::::DecimalConversionFail)?; + + // Emit Deposit event + Self::deposit_event(Event::Deposit { + dest_domain_id, + resource_id, + deposit_nonce, + sender: sender.clone(), + transfer_type, + deposit_data: Self::create_deposit_data(decimal_converted_amount, recipient), + handler_response: vec![], + }); + + // Emit FeeCollected event + Self::deposit_event(Event::FeeCollected { + fee_payer: sender, + dest_domain_id, + resource_id, + fee_amount: fee, + fee_asset_id: asset.id, + }); + + Ok(()) + } + + /// This method is used to trigger the process for retrying failed deposits on the MPC side. + #[transactional] + #[pallet::call_index(6)] + #[pallet::weight(< T as Config >::WeightInfo::retry())] + pub fn retry( + origin: OriginFor, + deposit_on_block_height: u128, + dest_domain_id: DomainID, + ) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"retry".to_vec(), @@ -545,91 +548,91 @@ pub mod pallet { ), Error::::AccessDenied ); - ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); - ensure!(!IsPaused::::get(dest_domain_id), Error::::BridgePaused); - ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); - - // Emit retry event - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::::Retry { - deposit_on_block_height, - dest_domain_id, - sender, - }); - Ok(()) - } - - /// Executes a batch of deposit proposals (only if signature is signed by MPC). - #[transactional] - #[pallet::call_index(7)] - #[pallet::weight(< T as Config >::WeightInfo::execute_proposal(proposals.len() as u32))] - pub fn execute_proposal( - _origin: OriginFor, - proposals: Vec, - signature: Vec, - ) -> DispatchResult { - // Check MPC address and bridge status - ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); - - ensure!(!proposals.is_empty(), Error::::EmptyProposalList); - - // parse proposals and construct signing message to meet EIP712 typed data - let final_message = Self::construct_ecdsa_signing_proposals_data(&proposals); - - // Verify MPC signature - ensure!( + ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); + ensure!(!IsPaused::::get(dest_domain_id), Error::::BridgePaused); + ensure!(DestDomainIds::::get(dest_domain_id), Error::::DestDomainNotSupported); + + // Emit retry event + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::::Retry { + deposit_on_block_height, + dest_domain_id, + sender, + }); + Ok(()) + } + + /// Executes a batch of deposit proposals (only if signature is signed by MPC). + #[transactional] + #[pallet::call_index(7)] + #[pallet::weight(< T as Config >::WeightInfo::execute_proposal(proposals.len() as u32))] + pub fn execute_proposal( + _origin: OriginFor, + proposals: Vec, + signature: Vec, + ) -> DispatchResult { + // Check MPC address and bridge status + ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); + + ensure!(!proposals.is_empty(), Error::::EmptyProposalList); + + // parse proposals and construct signing message to meet EIP712 typed data + let final_message = Self::construct_ecdsa_signing_proposals_data(&proposals); + + // Verify MPC signature + ensure!( Self::verify_by_mpc_address(final_message, signature), Error::::BadMpcSignature ); - // Execute proposals one by one. - // Note if one proposal failed to execute, we emit `FailedHandlerExecution` rather - // than revert whole transaction - for proposal in proposals.iter() { - Self::execute_proposal_internal(proposal).map_or_else( - |e| { - let err_msg: &'static str = e.into(); - // Any error during proposal list execution will emit FailedHandlerExecution - Self::deposit_event(Event::FailedHandlerExecution { - error: err_msg.as_bytes().to_vec(), - origin_domain_id: proposal.origin_domain_id, - deposit_nonce: proposal.deposit_nonce, - }); - }, - |_| { - // Update proposal status - Self::set_proposal_executed( - proposal.deposit_nonce, - proposal.origin_domain_id, - ); - - // Emit ProposalExecution - Self::deposit_event(Event::ProposalExecution { - origin_domain_id: proposal.origin_domain_id, - deposit_nonce: proposal.deposit_nonce, - data_hash: keccak_256( - &[ - proposal.data.clone(), - T::PalletId::get().into_account_truncating(), - ] - .concat(), - ), - }); - }, - ); - } - - Ok(()) - } - - /// Pause all registered bridges - #[pallet::call_index(8)] - #[pallet::weight(< T as Config >::WeightInfo::pause_all_bridges())] - pub fn pause_all_bridges(origin: OriginFor) -> DispatchResult { - ensure!( + // Execute proposals one by one. + // Note if one proposal failed to execute, we emit `FailedHandlerExecution` rather + // than revert whole transaction + for proposal in proposals.iter() { + Self::execute_proposal_internal(proposal).map_or_else( + |e| { + let err_msg: &'static str = e.into(); + // Any error during proposal list execution will emit FailedHandlerExecution + Self::deposit_event(Event::FailedHandlerExecution { + error: err_msg.as_bytes().to_vec(), + origin_domain_id: proposal.origin_domain_id, + deposit_nonce: proposal.deposit_nonce, + }); + }, + |_| { + // Update proposal status + Self::set_proposal_executed( + proposal.deposit_nonce, + proposal.origin_domain_id, + ); + + // Emit ProposalExecution + Self::deposit_event(Event::ProposalExecution { + origin_domain_id: proposal.origin_domain_id, + deposit_nonce: proposal.deposit_nonce, + data_hash: keccak_256( + &[ + proposal.data.clone(), + T::PalletId::get().into_account_truncating(), + ] + .concat(), + ), + }); + }, + ); + } + + Ok(()) + } + + /// Pause all registered bridges + #[pallet::call_index(8)] + #[pallet::weight(< T as Config >::WeightInfo::pause_all_bridges())] + pub fn pause_all_bridges(origin: OriginFor) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"pause_all_bridges".to_vec(), @@ -638,24 +641,24 @@ pub mod pallet { Error::::AccessDenied ); - // Pause all bridges - Self::pause_all_domains(); + // Pause all bridges + Self::pause_all_domains(); - // Emit AllBridgePaused - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::AllBridgePaused { sender }); + // Emit AllBridgePaused + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::AllBridgePaused { sender }); - Ok(()) - } + Ok(()) + } - /// Unpause all registered bridges - #[pallet::call_index(9)] - #[pallet::weight(< T as Config >::WeightInfo::unpause_all_bridges())] - pub fn unpause_all_bridges(origin: OriginFor) -> DispatchResult { - ensure!( + /// Unpause all registered bridges + #[pallet::call_index(9)] + #[pallet::weight(< T as Config >::WeightInfo::unpause_all_bridges())] + pub fn unpause_all_bridges(origin: OriginFor) -> DispatchResult { + ensure!( >::has_access( ::PalletIndex::get(), b"unpause_all_bridges".to_vec(), @@ -664,623 +667,622 @@ pub mod pallet { Error::::AccessDenied ); - // Make sure MPC address is setup - ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); - - // Unpause all bridges - Self::unpause_all_domains(); - - // Emit AllBridgeUnpaused - let sender = match ensure_signed(origin) { - Ok(sender) => sender, - _ => [0u8; 32].into(), - }; - Self::deposit_event(Event::AllBridgeUnpaused { sender }); - - Ok(()) - } - } - - impl Bridge for Pallet where - ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, - { - fn transfer(sender: [u8; 32], - asset: MultiAsset, - dest: MultiLocation) -> DispatchResult { - let sender_origin = OriginFor::::from(RawOrigin::Signed(sender.into())); - Pallet::::deposit(sender_origin, Box::from(asset), Box::from(dest))?; - - Ok(()) - } - } - - impl Pallet - where - ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, - { - /// Verifies that EIP712 typed proposal data is signed by MPC address - #[allow(dead_code)] - fn verify_by_mpc_address(signing_message: [u8; 32], signature: Vec) -> bool { - let sig = match signature.try_into() { - Ok(_sig) => _sig, - Err(error) => return false, - }; - - // recover the signing address - if let Ok(pubkey) = - // recover the uncompressed pubkey - secp256k1_ecdsa_recover(&sig, &signing_message) - { - let address = Self::public_key_to_address(&pubkey); - - address == MpcAddr::::get().0 - } else { - false - } - } - - /// Return the TokenReservedAccount address by the given token - pub fn get_token_reserved_account(token_id: &AssetId) -> Option<[u8; 32]> { - T::TransferReserveAccounts::get() - .get(token_id) - .map(|account| (*account).clone().into()) - } - - /// convert the ECDSA 64-byte uncompressed pubkey to H160 address - pub fn public_key_to_address(public_key: &[u8]) -> [u8; 20] { - let hash = keccak_256(public_key); - let final_hash = array_ref![&hash, 12, 20]; - *final_hash - } - - /// Parse proposals and construct the original signing message - pub fn construct_ecdsa_signing_proposals_data(proposals: &Vec) -> [u8; 32] { - let proposals_typehash = keccak_256( + // Make sure MPC address is setup + ensure!(!MpcAddr::::get().is_clear(), Error::::MissingMpcAddress); + + // Unpause all bridges + Self::unpause_all_domains(); + + // Emit AllBridgeUnpaused + let sender = match ensure_signed(origin) { + Ok(sender) => sender, + _ => [0u8; 32].into(), + }; + Self::deposit_event(Event::AllBridgeUnpaused { sender }); + + Ok(()) + } + } + + impl Bridge for Pallet + where + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, + { + fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult { + let sender_origin = OriginFor::::from(RawOrigin::Signed(sender.into())); + Pallet::::deposit(sender_origin, Box::from(asset), Box::from(dest))?; + + Ok(()) + } + } + + impl Pallet + where + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, + { + /// Verifies that EIP712 typed proposal data is signed by MPC address + #[allow(dead_code)] + fn verify_by_mpc_address(signing_message: [u8; 32], signature: Vec) -> bool { + let sig = match signature.try_into() { + Ok(_sig) => _sig, + Err(error) => return false, + }; + + // recover the signing address + if let Ok(pubkey) = + // recover the uncompressed pubkey + secp256k1_ecdsa_recover(&sig, &signing_message) + { + let address = Self::public_key_to_address(&pubkey); + + address == MpcAddr::::get().0 + } else { + false + } + } + + /// Return the TokenReservedAccount address by the given token + pub fn get_token_reserved_account(token_id: &AssetId) -> Option<[u8; 32]> { + T::TransferReserveAccounts::get() + .get(token_id) + .map(|account| (*account).clone().into()) + } + + /// convert the ECDSA 64-byte uncompressed pubkey to H160 address + pub fn public_key_to_address(public_key: &[u8]) -> [u8; 20] { + let hash = keccak_256(public_key); + let final_hash = array_ref![&hash, 12, 20]; + *final_hash + } + + /// Parse proposals and construct the original signing message + pub fn construct_ecdsa_signing_proposals_data(proposals: &Vec) -> [u8; 32] { + let proposals_typehash = keccak_256( "Proposals(Proposal[] proposals)Proposal(uint8 originDomainID,uint64 depositNonce,bytes32 resourceID,bytes data)" .as_bytes(), ); - let proposal_typehash = keccak_256( - "Proposal(uint8 originDomainID,uint64 depositNonce,bytes32 resourceID,bytes data)" - .as_bytes(), - ); + let proposal_typehash = keccak_256( + "Proposal(uint8 originDomainID,uint64 depositNonce,bytes32 resourceID,bytes data)" + .as_bytes(), + ); - if proposals.is_empty() { - return [0u8; 32]; - } - - let mut keccak_data = Vec::new(); - for prop in proposals { - let proposal_domain_id_token = Token::Uint(prop.origin_domain_id.into()); - let proposal_deposit_nonce_token = Token::Uint(prop.deposit_nonce.into()); - let proposal_resource_id_token = Token::FixedBytes(prop.resource_id.to_vec()); - let proposal_data_token = Token::FixedBytes(keccak_256(&prop.data).to_vec()); - - keccak_data.push(keccak_256(&abi_encode(&[ - Token::FixedBytes(proposal_typehash.to_vec()), - proposal_domain_id_token, - proposal_deposit_nonce_token, - proposal_resource_id_token, - proposal_data_token, - ]))); - } - - // flatten the keccak_data into vec - let mut final_keccak_data = Vec::new(); - for data in keccak_data { - for d in data { - final_keccak_data.push(d) - } - } - - let final_keccak_data_input = &vec![SolidityDataType::Bytes(&final_keccak_data)]; - let bytes = encode_packed(final_keccak_data_input); - let hashed_keccak_data = keccak_256(bytes.as_slice()); - - let struct_hash = keccak_256(&abi_encode(&[ - Token::FixedBytes(proposals_typehash.to_vec()), - Token::FixedBytes(hashed_keccak_data.to_vec()), - ])); - - // domain separator - let default_eip712_domain = eip712::EIP712Domain::default(); - let eip712_domain = eip712::EIP712Domain { - name: b"Bridge".to_vec(), - version: b"3.1.0".to_vec(), - chain_id: T::EIP712ChainID::get(), - verifying_contract: T::DestVerifyingContractAddress::get(), - salt: default_eip712_domain.salt, - }; - let domain_separator = eip712_domain.separator(); - - let typed_data_hash_input = &vec![ - SolidityDataType::String("\x19\x01"), - SolidityDataType::Bytes(&domain_separator), - SolidityDataType::Bytes(&struct_hash), - ]; - let bytes = encode_packed(typed_data_hash_input); - keccak_256(bytes.as_slice()) - } - - /// Extract asset id and transfer amount from `MultiAsset`, currently only fungible asset - /// are supported. - fn extract_asset(asset: &MultiAsset) -> Option<(ResourceId, u128, TransferType)> { - match (&asset.fun, &asset.id) { - (Fungible(amount), _) => { - T::ResourcePairs::get().iter().position(|a| a.0 == asset.id).map(|idx| { - (T::ResourcePairs::get()[idx].1, *amount, TransferType::FungibleTransfer) - }) - } - _ => None, - } - } - - pub fn create_deposit_data(amount: u128, recipient: Vec) -> Vec { - [ - &Self::hex_zero_padding_32(amount), - &Self::hex_zero_padding_32(recipient.len() as u128), - recipient.as_slice(), - ] - .concat() - .to_vec() - } - - /// Extract transfer amount and recipient location from deposit data. - /// For fungible transfer, data passed into the function should be constructed as follows: - /// amount uint256 bytes 0 - 32 - /// recipient data length uint256 bytes 32 - 64 - /// recipient data bytes bytes 64 - END - /// - /// Only fungible transfer is supported so far. - fn extract_deposit_data(data: &Vec) -> Result<(u128, MultiLocation), DispatchError> { - if data.len() < 64 { - return Err(Error::::InvalidDepositData.into()); - } - - let amount: u128 = U256::from_big_endian(&data[0..32]) - .try_into() - .map_err(|_| Error::::InvalidDepositData)?; - let recipient_len: usize = U256::from_big_endian(&data[32..64]) - .try_into() - .map_err(|_| Error::::InvalidDepositData)?; - if (data.len() - 64) != recipient_len { - return Err(Error::::InvalidDepositData.into()); - } - - let recipient = data[64..data.len()].to_vec(); - if let Ok(location) = ::decode(&mut recipient.as_slice()) { - Ok((amount, location)) - } else { - Err(Error::::InvalidDepositData.into()) - } - } - - fn rid_to_assetid(rid: &ResourceId) -> Option { - T::ResourcePairs::get() - .iter() - .position(|a| &a.1 == rid) - .map(|idx| T::ResourcePairs::get()[idx].0) - } - - fn hex_zero_padding_32(i: u128) -> [u8; 32] { - let mut result = [0u8; 32]; - U256::from(i).to_big_endian(&mut result); - result - } - - /// Return true if deposit nonce has been used - pub fn is_proposal_executed(nonce: DepositNonce, domain_id: DomainID) -> bool { - (UsedNonces::::get(domain_id, nonce / 64) & (1 << (nonce % 64))) != 0 - } - - /// Set bit mask for specific nonce as used - fn set_proposal_executed(nonce: DepositNonce, domain_id: DomainID) { - let mut current_nonces = UsedNonces::::get(domain_id, nonce / 64); - current_nonces |= 1 << (nonce % 64); - UsedNonces::::insert(domain_id, nonce / 64, current_nonces); - } - - /// Execute a single proposal - fn execute_proposal_internal(proposal: &Proposal) -> DispatchResult { - // Check if dest domain bridge is paused - ensure!(!IsPaused::::get(proposal.origin_domain_id), Error::::BridgePaused); - // Check if domain is supported - ensure!( + if proposals.is_empty() { + return [0u8; 32]; + } + + let mut keccak_data = Vec::new(); + for prop in proposals { + let proposal_domain_id_token = Token::Uint(prop.origin_domain_id.into()); + let proposal_deposit_nonce_token = Token::Uint(prop.deposit_nonce.into()); + let proposal_resource_id_token = Token::FixedBytes(prop.resource_id.to_vec()); + let proposal_data_token = Token::FixedBytes(keccak_256(&prop.data).to_vec()); + + keccak_data.push(keccak_256(&abi_encode(&[ + Token::FixedBytes(proposal_typehash.to_vec()), + proposal_domain_id_token, + proposal_deposit_nonce_token, + proposal_resource_id_token, + proposal_data_token, + ]))); + } + + // flatten the keccak_data into vec + let mut final_keccak_data = Vec::new(); + for data in keccak_data { + for d in data { + final_keccak_data.push(d) + } + } + + let final_keccak_data_input = &vec![SolidityDataType::Bytes(&final_keccak_data)]; + let bytes = encode_packed(final_keccak_data_input); + let hashed_keccak_data = keccak_256(bytes.as_slice()); + + let struct_hash = keccak_256(&abi_encode(&[ + Token::FixedBytes(proposals_typehash.to_vec()), + Token::FixedBytes(hashed_keccak_data.to_vec()), + ])); + + // domain separator + let default_eip712_domain = eip712::EIP712Domain::default(); + let eip712_domain = eip712::EIP712Domain { + name: b"Bridge".to_vec(), + version: b"3.1.0".to_vec(), + chain_id: T::EIP712ChainID::get(), + verifying_contract: T::DestVerifyingContractAddress::get(), + salt: default_eip712_domain.salt, + }; + let domain_separator = eip712_domain.separator(); + + let typed_data_hash_input = &vec![ + SolidityDataType::String("\x19\x01"), + SolidityDataType::Bytes(&domain_separator), + SolidityDataType::Bytes(&struct_hash), + ]; + let bytes = encode_packed(typed_data_hash_input); + keccak_256(bytes.as_slice()) + } + + /// Extract asset id and transfer amount from `MultiAsset`, currently only fungible asset + /// are supported. + fn extract_asset(asset: &MultiAsset) -> Option<(ResourceId, u128, TransferType)> { + match (&asset.fun, &asset.id) { + (Fungible(amount), _) => { + T::ResourcePairs::get().iter().position(|a| a.0 == asset.id).map(|idx| { + (T::ResourcePairs::get()[idx].1, *amount, TransferType::FungibleTransfer) + }) + }, + _ => None, + } + } + + pub fn create_deposit_data(amount: u128, recipient: Vec) -> Vec { + [ + &Self::hex_zero_padding_32(amount), + &Self::hex_zero_padding_32(recipient.len() as u128), + recipient.as_slice(), + ] + .concat() + .to_vec() + } + + /// Extract transfer amount and recipient location from deposit data. + /// For fungible transfer, data passed into the function should be constructed as follows: + /// amount uint256 bytes 0 - 32 + /// recipient data length uint256 bytes 32 - 64 + /// recipient data bytes bytes 64 - END + /// + /// Only fungible transfer is supported so far. + fn extract_deposit_data(data: &Vec) -> Result<(u128, MultiLocation), DispatchError> { + if data.len() < 64 { + return Err(Error::::InvalidDepositData.into()); + } + + let amount: u128 = U256::from_big_endian(&data[0..32]) + .try_into() + .map_err(|_| Error::::InvalidDepositData)?; + let recipient_len: usize = U256::from_big_endian(&data[32..64]) + .try_into() + .map_err(|_| Error::::InvalidDepositData)?; + if (data.len() - 64) != recipient_len { + return Err(Error::::InvalidDepositData.into()); + } + + let recipient = data[64..data.len()].to_vec(); + if let Ok(location) = ::decode(&mut recipient.as_slice()) { + Ok((amount, location)) + } else { + Err(Error::::InvalidDepositData.into()) + } + } + + fn rid_to_assetid(rid: &ResourceId) -> Option { + T::ResourcePairs::get() + .iter() + .position(|a| &a.1 == rid) + .map(|idx| T::ResourcePairs::get()[idx].0) + } + + fn hex_zero_padding_32(i: u128) -> [u8; 32] { + let mut result = [0u8; 32]; + U256::from(i).to_big_endian(&mut result); + result + } + + /// Return true if deposit nonce has been used + pub fn is_proposal_executed(nonce: DepositNonce, domain_id: DomainID) -> bool { + (UsedNonces::::get(domain_id, nonce / 64) & (1 << (nonce % 64))) != 0 + } + + /// Set bit mask for specific nonce as used + fn set_proposal_executed(nonce: DepositNonce, domain_id: DomainID) { + let mut current_nonces = UsedNonces::::get(domain_id, nonce / 64); + current_nonces |= 1 << (nonce % 64); + UsedNonces::::insert(domain_id, nonce / 64, current_nonces); + } + + /// Execute a single proposal + fn execute_proposal_internal(proposal: &Proposal) -> DispatchResult { + // Check if dest domain bridge is paused + ensure!(!IsPaused::::get(proposal.origin_domain_id), Error::::BridgePaused); + // Check if domain is supported + ensure!( DestDomainIds::::get(proposal.origin_domain_id), Error::::DestDomainNotSupported ); - // Check if proposal has executed - ensure!( + // Check if proposal has executed + ensure!( !Self::is_proposal_executed(proposal.deposit_nonce, proposal.origin_domain_id), Error::::ProposalAlreadyComplete ); - // Extract ResourceId from proposal data to get corresponding asset (MultiAsset) - let asset_id = - Self::rid_to_assetid(&proposal.resource_id).ok_or(Error::::AssetNotBound)?; - // Extract Receipt from proposal data to get corresponding location (MultiLocation) - let (amount, location) = Self::extract_deposit_data(&proposal.data)?; - - // convert the asset decimal - let decimal_converted_asset = - T::DecimalConverter::convert_from(&(asset_id, amount).into()) - .ok_or(Error::::DecimalConversionFail)?; - - let token_reserved_account = Self::get_token_reserved_account(&asset_id) - .ok_or(Error::::NoLiquidityHolderAccountBound)?; - - // Withdraw `decimal_converted_asset` of asset from reserve account - if T::IsReserve::contains(&decimal_converted_asset, &MultiLocation::here()) { - T::AssetTransactor::withdraw_asset( - &decimal_converted_asset, - &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), - None, - ) - .map_err(|_| Error::::TransactFailed)?; - } - - // Deposit `decimal_converted_asset` of asset to dest location - T::AssetTransactor::deposit_asset( - &decimal_converted_asset, - &location, - // Put empty message hash here because we are not sending XCM message - &XcmContext::with_message_id([0; 32]), - ) - .map_err(|_| Error::::TransactFailed)?; - - Ok(()) - } - - /// unpause all registered domains in the storage - fn unpause_all_domains() { - DestDomainIds::::iter_keys().for_each(|d| IsPaused::::insert(d, false)); - IsPaused::::iter_keys().for_each(|d| IsPaused::::insert(d, false)); - } - - /// pause all registered domains in the storage - fn pause_all_domains() { - DestDomainIds::::iter_keys().for_each(|d| IsPaused::::insert(d, true)); - IsPaused::::iter_keys().for_each(|d| IsPaused::::insert(d, true)); - } - } - - #[cfg(test)] - mod test { - use codec::{self, Encode}; - use frame_support::{ - assert_noop, assert_ok, crypto::ecdsa::ECDSAExt, - traits::tokens::fungibles::Create as FungibleCerate, - }; - use parachains_common::AccountId; - use primitive_types::U256; - use sp_core::{ByteArray, ecdsa, Pair}; - use sp_std::{boxed::Box, vec}; - use xcm::latest::prelude::*; - - use bridge::mock::{ - AccessSegregator, ALICE, assert_events, ASSET_OWNER, Assets, Balances, - BOB, BridgeAccountNative, BridgeAccountOtherTokens, BridgePalletIndex, - DEST_DOMAIN_ID, ENDOWED_BALANCE, NativeLocation, NativeResourceId, new_test_ext, - Runtime, RuntimeEvent, RuntimeOrigin as Origin, slice_to_generalkey, - SygmaBasicFeeHandler, SygmaBridge, SygmaFeeHandlerRouter, SygmaPercentageFeeHandler, TreasuryAccount, UsdtAssetId, UsdtLocation, - UsdtResourceId, - }; - use sygma_fee_handler_router::FeeHandlerType; - use sygma_traits::{DomainID, MpcAddress, TransferType}; - - use crate as bridge; - use crate::{ - DestChainIds, - DestDomainIds, Error, Event as SygmaBridgeEvent, IsPaused, mock::{AstrAssetId, AstrLocation, AstrResourceId}, MpcAddr, - Proposal, - }; - - #[test] - fn get_token_reserved_account_test() { - new_test_ext().execute_with(|| { - assert_eq!( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()).unwrap(), - BridgeAccountOtherTokens::get().as_slice() - ); - assert_eq!( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()).unwrap(), - BridgeAccountNative::get().as_slice() - ); - assert_eq!( - SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()).unwrap(), - BridgeAccountOtherTokens::get().as_slice() - ); - - // unknown token should return None - assert_eq!( - SygmaBridge::get_token_reserved_account( - &MultiLocation::new( - 2, - X3( - Parachain(1000), - slice_to_generalkey(b"sygma"), - slice_to_generalkey(b"unknown"), - ), - ) - .into() - ), - None - ); - }) - } - - #[test] - fn set_mpc_address() { - new_test_ext().execute_with(|| { - let default_addr: MpcAddress = MpcAddress::default(); - let test_mpc_addr_a: MpcAddress = MpcAddress([1u8; 20]); - let test_mpc_addr_b: MpcAddress = MpcAddress([2u8; 20]); - - assert_eq!(MpcAddr::::get(), default_addr); - - // set to test_mpc_addr_a - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr_a)); - assert_eq!(MpcAddr::::get(), test_mpc_addr_a); - - // set to test_mpc_addr_b: should be MpcAddrNotUpdatable error - assert_noop!( + // Extract ResourceId from proposal data to get corresponding asset (MultiAsset) + let asset_id = + Self::rid_to_assetid(&proposal.resource_id).ok_or(Error::::AssetNotBound)?; + // Extract Receipt from proposal data to get corresponding location (MultiLocation) + let (amount, location) = Self::extract_deposit_data(&proposal.data)?; + + // convert the asset decimal + let decimal_converted_asset = + T::DecimalConverter::convert_from(&(asset_id, amount).into()) + .ok_or(Error::::DecimalConversionFail)?; + + let token_reserved_account = Self::get_token_reserved_account(&asset_id) + .ok_or(Error::::NoLiquidityHolderAccountBound)?; + + // Withdraw `decimal_converted_asset` of asset from reserve account + if T::IsReserve::contains(&decimal_converted_asset, &MultiLocation::here()) { + T::AssetTransactor::withdraw_asset( + &decimal_converted_asset, + &Junction::AccountId32 { network: None, id: token_reserved_account }.into(), + None, + ) + .map_err(|_| Error::::TransactFailed)?; + } + + // Deposit `decimal_converted_asset` of asset to dest location + T::AssetTransactor::deposit_asset( + &decimal_converted_asset, + &location, + // Put empty message hash here because we are not sending XCM message + &XcmContext::with_message_id([0; 32]), + ) + .map_err(|_| Error::::TransactFailed)?; + + Ok(()) + } + + /// unpause all registered domains in the storage + fn unpause_all_domains() { + DestDomainIds::::iter_keys().for_each(|d| IsPaused::::insert(d, false)); + IsPaused::::iter_keys().for_each(|d| IsPaused::::insert(d, false)); + } + + /// pause all registered domains in the storage + fn pause_all_domains() { + DestDomainIds::::iter_keys().for_each(|d| IsPaused::::insert(d, true)); + IsPaused::::iter_keys().for_each(|d| IsPaused::::insert(d, true)); + } + } + + #[cfg(test)] + mod test { + use codec::{self, Encode}; + use frame_support::{ + assert_noop, assert_ok, crypto::ecdsa::ECDSAExt, + traits::tokens::fungibles::Create as FungibleCerate, + }; + use parachains_common::AccountId; + use primitive_types::U256; + use sp_core::{ecdsa, ByteArray, Pair}; + use sp_std::{boxed::Box, vec}; + use xcm::latest::prelude::*; + + use bridge::mock::{ + assert_events, new_test_ext, slice_to_generalkey, AccessSegregator, Assets, Balances, + BridgeAccountNative, BridgeAccountOtherTokens, BridgePalletIndex, NativeLocation, + NativeResourceId, Runtime, RuntimeEvent, RuntimeOrigin as Origin, SygmaBasicFeeHandler, + SygmaBridge, SygmaFeeHandlerRouter, SygmaPercentageFeeHandler, TreasuryAccount, + UsdtAssetId, UsdtLocation, UsdtResourceId, ALICE, ASSET_OWNER, BOB, DEST_DOMAIN_ID, + ENDOWED_BALANCE, + }; + use sygma_fee_handler_router::FeeHandlerType; + use sygma_traits::{Bridge, DomainID, MpcAddress, TransferType}; + + use crate as bridge; + use crate::{ + mock::{AstrAssetId, AstrLocation, AstrResourceId}, + DestChainIds, DestDomainIds, Error, Event as SygmaBridgeEvent, IsPaused, MpcAddr, + Proposal, + }; + + #[test] + fn get_token_reserved_account_test() { + new_test_ext().execute_with(|| { + assert_eq!( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()).unwrap(), + BridgeAccountOtherTokens::get().as_slice() + ); + assert_eq!( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()).unwrap(), + BridgeAccountNative::get().as_slice() + ); + assert_eq!( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()).unwrap(), + BridgeAccountOtherTokens::get().as_slice() + ); + + // unknown token should return None + assert_eq!( + SygmaBridge::get_token_reserved_account( + &MultiLocation::new( + 2, + X3( + Parachain(1000), + slice_to_generalkey(b"sygma"), + slice_to_generalkey(b"unknown"), + ), + ) + .into() + ), + None + ); + }) + } + + #[test] + fn set_mpc_address() { + new_test_ext().execute_with(|| { + let default_addr: MpcAddress = MpcAddress::default(); + let test_mpc_addr_a: MpcAddress = MpcAddress([1u8; 20]); + let test_mpc_addr_b: MpcAddress = MpcAddress([2u8; 20]); + + assert_eq!(MpcAddr::::get(), default_addr); + + // set to test_mpc_addr_a + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr_a)); + assert_eq!(MpcAddr::::get(), test_mpc_addr_a); + + // set to test_mpc_addr_b: should be MpcAddrNotUpdatable error + assert_noop!( SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr_b), bridge::Error::::MpcAddrNotUpdatable ); - // permission test: unauthorized account should not be able to set mpc address - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // permission test: unauthorized account should not be able to set mpc address + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::set_mpc_address(unauthorized_account, test_mpc_addr_a), bridge::Error::::AccessDenied ); - assert_eq!(MpcAddr::::get(), test_mpc_addr_a); - }) - } + assert_eq!(MpcAddr::::get(), test_mpc_addr_a); + }) + } - #[test] - fn pause_bridge() { - new_test_ext().execute_with(|| { - let default_addr = MpcAddress::default(); - assert_eq!(MpcAddr::::get(), default_addr); + #[test] + fn pause_bridge() { + new_test_ext().execute_with(|| { + let default_addr = MpcAddress::default(); + assert_eq!(MpcAddr::::get(), default_addr); - // register domain - assert_ok!(SygmaBridge::register_domain( + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // pause bridge, should be ok - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(IsPaused::::get(DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { - dest_domain_id: DEST_DOMAIN_ID, - })]); + // pause bridge, should be ok + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(IsPaused::::get(DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { + dest_domain_id: DEST_DOMAIN_ID, + })]); - // pause bridge again after paused, should be ok - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(IsPaused::::get(DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { - dest_domain_id: DEST_DOMAIN_ID, - })]); + // pause bridge again after paused, should be ok + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(IsPaused::::get(DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { + dest_domain_id: DEST_DOMAIN_ID, + })]); - // permission test: unauthorized account should not be able to pause bridge - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // permission test: unauthorized account should not be able to pause bridge + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::pause_bridge(unauthorized_account, DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - assert!(IsPaused::::get(DEST_DOMAIN_ID)); - }) - } + assert!(IsPaused::::get(DEST_DOMAIN_ID)); + }) + } - #[test] - fn unpause_bridge() { - new_test_ext().execute_with(|| { - let default_addr: MpcAddress = MpcAddress::default(); - assert_eq!(MpcAddr::::get(), default_addr); + #[test] + fn unpause_bridge() { + new_test_ext().execute_with(|| { + let default_addr: MpcAddress = MpcAddress::default(); + assert_eq!(MpcAddr::::get(), default_addr); - // register domain - assert_ok!(SygmaBridge::register_domain( + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { - dest_domain_id: DEST_DOMAIN_ID, - })]); + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgePaused { + dest_domain_id: DEST_DOMAIN_ID, + })]); - // bridge should be paused here - assert!(IsPaused::::get(DEST_DOMAIN_ID)); + // bridge should be paused here + assert!(IsPaused::::get(DEST_DOMAIN_ID)); - // ready to unpause bridge, should be ok - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgeUnpaused { - dest_domain_id: DEST_DOMAIN_ID, - })]); + // ready to unpause bridge, should be ok + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::BridgeUnpaused { + dest_domain_id: DEST_DOMAIN_ID, + })]); - // try to unpause it again, should be error - assert_noop!( + // try to unpause it again, should be error + assert_noop!( SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID), bridge::Error::::BridgeUnpaused ); - // permission test: unauthorized account should not be able to unpause a recognized - // bridge - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // permission test: unauthorized account should not be able to unpause a recognized + // bridge + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::unpause_bridge(unauthorized_account, DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - assert!(!IsPaused::::get(DEST_DOMAIN_ID)); - }) - } - - #[test] - fn verify_mpc_signature_invalid_signature() { - new_test_ext().execute_with(|| { - let signature = vec![1u8]; - - // dummy proposals - let p1 = Proposal { - origin_domain_id: 1, - deposit_nonce: 1, - resource_id: [1u8; 32], - data: vec![1u8], - }; - let p2 = Proposal { - origin_domain_id: 2, - deposit_nonce: 2, - resource_id: [2u8; 32], - data: vec![2u8], - }; - let proposals = vec![p1, p2]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - - // should be false - assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); - }) - } - - #[test] - fn verify_mpc_signature_invalid_message() { - new_test_ext().execute_with(|| { - // generate mpc keypair - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let public = pair.public(); - let message = b"Something important"; - let signature = pair.sign(&message[..]); - - // make sure generated keypair, message and signature are all good - assert!(ecdsa::Pair::verify(&signature, &message[..], &public)); - assert!(!ecdsa::Pair::verify(&signature, b"Something else", &public)); - - // dummy proposals - let p1 = Proposal { - origin_domain_id: 1, - deposit_nonce: 1, - resource_id: [1u8; 32], - data: vec![1u8], - }; - let p2 = Proposal { - origin_domain_id: 2, - deposit_nonce: 2, - resource_id: [2u8; 32], - data: vec![2u8], - }; - let proposals = vec![p1, p2]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - - // verify non matched signature against proposal list, should be false - assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); - }) - } - - #[test] - fn verify_mpc_signature_valid_message_unmatched_mpc() { - new_test_ext().execute_with(|| { - // generate the signing keypair - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - - // set mpc address to another random key - let test_mpc_addr: MpcAddress = MpcAddress([7u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_eq!(MpcAddr::::get(), test_mpc_addr); - - // dummy proposals - let p1 = Proposal { - origin_domain_id: 1, - deposit_nonce: 1, - resource_id: [1u8; 32], - data: vec![1u8], - }; - let p2 = Proposal { - origin_domain_id: 2, - deposit_nonce: 2, - resource_id: [2u8; 32], - data: vec![2u8], - }; - let proposals = vec![p1, p2]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - - // sign final message using generated prikey - let signature = pair.sign_prehashed(&final_message); - - // verify signature, should be false because the signing address != mpc address - assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); - }) - } - - #[test] - fn verify_mpc_signature_valid_message_valid_signature() { - new_test_ext().execute_with(|| { - // generate mpc keypair - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); - - // set mpc address to generated keypair's address - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_eq!(MpcAddr::::get(), test_mpc_addr); - - // dummy proposals - let p1 = Proposal { - origin_domain_id: 1, - deposit_nonce: 1, - resource_id: [1u8; 32], - data: vec![1u8], - }; - let p2 = Proposal { - origin_domain_id: 2, - deposit_nonce: 2, - resource_id: [2u8; 32], - data: vec![2u8], - }; - let proposals = vec![p1, p2]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - - // sign final message using generated mpc prikey - // `pari.sign` will hash the final message into blake2_256 then sign it, so use - // sign_prehashed here - let signature = pair.sign_prehashed(&final_message); - - // verify signature, should be true - assert!(SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); - }) - } - - #[test] - fn deposit_native_asset_should_work() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 1_000_000_000_000u128; // 1 with 12 decimals - let amount = 200_000_000_000_000u128; // 200 with 12 decimals - let final_amount_in_deposit_event = 199_000_000_000_000_000_000; // 200 - 1 then adjust to 18 decimals - - assert_ok!(SygmaBridge::register_domain( + assert!(!IsPaused::::get(DEST_DOMAIN_ID)); + }) + } + + #[test] + fn verify_mpc_signature_invalid_signature() { + new_test_ext().execute_with(|| { + let signature = vec![1u8]; + + // dummy proposals + let p1 = Proposal { + origin_domain_id: 1, + deposit_nonce: 1, + resource_id: [1u8; 32], + data: vec![1u8], + }; + let p2 = Proposal { + origin_domain_id: 2, + deposit_nonce: 2, + resource_id: [2u8; 32], + data: vec![2u8], + }; + let proposals = vec![p1, p2]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + + // should be false + assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); + }) + } + + #[test] + fn verify_mpc_signature_invalid_message() { + new_test_ext().execute_with(|| { + // generate mpc keypair + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let public = pair.public(); + let message = b"Something important"; + let signature = pair.sign(&message[..]); + + // make sure generated keypair, message and signature are all good + assert!(ecdsa::Pair::verify(&signature, &message[..], &public)); + assert!(!ecdsa::Pair::verify(&signature, b"Something else", &public)); + + // dummy proposals + let p1 = Proposal { + origin_domain_id: 1, + deposit_nonce: 1, + resource_id: [1u8; 32], + data: vec![1u8], + }; + let p2 = Proposal { + origin_domain_id: 2, + deposit_nonce: 2, + resource_id: [2u8; 32], + data: vec![2u8], + }; + let proposals = vec![p1, p2]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + + // verify non matched signature against proposal list, should be false + assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); + }) + } + + #[test] + fn verify_mpc_signature_valid_message_unmatched_mpc() { + new_test_ext().execute_with(|| { + // generate the signing keypair + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + + // set mpc address to another random key + let test_mpc_addr: MpcAddress = MpcAddress([7u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_eq!(MpcAddr::::get(), test_mpc_addr); + + // dummy proposals + let p1 = Proposal { + origin_domain_id: 1, + deposit_nonce: 1, + resource_id: [1u8; 32], + data: vec![1u8], + }; + let p2 = Proposal { + origin_domain_id: 2, + deposit_nonce: 2, + resource_id: [2u8; 32], + data: vec![2u8], + }; + let proposals = vec![p1, p2]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + + // sign final message using generated prikey + let signature = pair.sign_prehashed(&final_message); + + // verify signature, should be false because the signing address != mpc address + assert!(!SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); + }) + } + + #[test] + fn verify_mpc_signature_valid_message_valid_signature() { + new_test_ext().execute_with(|| { + // generate mpc keypair + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); + + // set mpc address to generated keypair's address + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_eq!(MpcAddr::::get(), test_mpc_addr); + + // dummy proposals + let p1 = Proposal { + origin_domain_id: 1, + deposit_nonce: 1, + resource_id: [1u8; 32], + data: vec![1u8], + }; + let p2 = Proposal { + origin_domain_id: 2, + deposit_nonce: 2, + resource_id: [2u8; 32], + data: vec![2u8], + }; + let proposals = vec![p1, p2]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + + // sign final message using generated mpc prikey + // `pari.sign` will hash the final message into blake2_256 then sign it, so use + // sign_prehashed here + let signature = pair.sign_prehashed(&final_message); + + // verify signature, should be true + assert!(SygmaBridge::verify_by_mpc_address(final_message, signature.encode())); + }) + } + + #[test] + fn deposit_native_asset_should_work() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 1_000_000_000_000u128; // 1 with 12 decimals + let amount = 200_000_000_000_000u128; // 200 with 12 decimals + let final_amount_in_deposit_event = 199_000_000_000_000_000_000; // 200 - 1 then adjust to 18 decimals + + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -1291,123 +1293,197 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount - fee - ); - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - deposit_nonce: 0, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - final_amount_in_deposit_event, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - fee_amount: fee, - fee_asset_id: NativeLocation::get().into(), - }), - ]); - }) - } - - #[test] - fn hex_zero_padding_32_test() { - new_test_ext().execute_with(|| { - assert_eq!( - SygmaBridge::hex_zero_padding_32(100).to_vec(), - vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 100, - ] - ); - let recipient = String::from("0x95ECF5ae000e0fe0e0dE63aDE9b7D82a372038b4"); - assert_eq!( - SygmaBridge::hex_zero_padding_32(recipient.len() as u128).to_vec(), - vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 42, - ] - ); - }) - } - - #[test] - fn create_deposit_data_test() { - new_test_ext().execute_with(|| { - let recipient = b"0x95ECF5ae000e0fe0e0dE63aDE9b7D82a372038b4".to_vec(); - let data = SygmaBridge::create_deposit_data(100, recipient); - // 32 + 32 + 42 - assert_eq!(data.len(), 106); - assert_eq!( - data.to_vec(), - vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 48, 120, 57, 53, 69, 67, 70, - 53, 97, 101, 48, 48, 48, 101, 48, 102, 101, 48, 101, 48, 100, 69, 54, 51, - 97, 68, 69, 57, 98, 55, 68, 56, 50, 97, 51, 55, 50, 48, 51, 56, 98, 52, - ] - ); - }) - } - - #[test] - fn deposit_foreign_asset_should_work() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 100u128; - let amount = 200u128; - - assert_ok!(SygmaBasicFeeHandler::set_fee( + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + deposit_nonce: 0, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + final_amount_in_deposit_event, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + fee_amount: fee, + fee_asset_id: NativeLocation::get().into(), + }), + ]); + }) + } + + #[test] + fn transfer_wrap_deposit_should_work() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 1_000_000_000_000u128; // 1 with 12 decimals + let amount = 200_000_000_000_000u128; // 200 with 12 decimals + let final_amount_in_deposit_event = 199_000_000_000_000_000_000; // 200 - 1 then adjust to 18 decimals + + assert_ok!(SygmaBridge::register_domain( + Origin::root(), + DEST_DOMAIN_ID, + U256::from(1) + )); + assert_ok!(SygmaBasicFeeHandler::set_fee( + Origin::root(), + DEST_DOMAIN_ID, + Box::new(NativeLocation::get().into()), + fee + )); + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + Origin::root(), + DEST_DOMAIN_ID, + Box::new(NativeLocation::get().into()), + FeeHandlerType::BasicFeeHandler, + )); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + + let asset: MultiAsset = (Concrete(NativeLocation::get()), Fungible(amount)).into(); + let dest: MultiLocation = MultiLocation { + parents: 0, + interior: X2( + slice_to_generalkey(b"ethereum recipient"), + slice_to_generalkey(&[1]), + ), + }; + + // Call transfer instead of deposit + assert_ok!(SygmaBridge::transfer(ALICE.into(), asset.clone(), dest)); + + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + deposit_nonce: 0, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + final_amount_in_deposit_event, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + fee_amount: fee, + fee_asset_id: NativeLocation::get().into(), + }), + ]); + }) + } + + #[test] + fn hex_zero_padding_32_test() { + new_test_ext().execute_with(|| { + assert_eq!( + SygmaBridge::hex_zero_padding_32(100).to_vec(), + vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 100, + ] + ); + let recipient = String::from("0x95ECF5ae000e0fe0e0dE63aDE9b7D82a372038b4"); + assert_eq!( + SygmaBridge::hex_zero_padding_32(recipient.len() as u128).to_vec(), + vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 42, + ] + ); + }) + } + + #[test] + fn create_deposit_data_test() { + new_test_ext().execute_with(|| { + let recipient = b"0x95ECF5ae000e0fe0e0dE63aDE9b7D82a372038b4".to_vec(); + let data = SygmaBridge::create_deposit_data(100, recipient); + // 32 + 32 + 42 + assert_eq!(data.len(), 106); + assert_eq!( + data.to_vec(), + vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 48, 120, 57, 53, 69, 67, 70, + 53, 97, 101, 48, 48, 48, 101, 48, 102, 101, 48, 101, 48, 100, 69, 54, 51, + 97, 68, 69, 57, 98, 55, 68, 56, 50, 97, 51, 55, 50, 48, 51, 56, 98, 52, + ] + ); + }) + } + + #[test] + fn deposit_foreign_asset_should_work() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 100u128; + let amount = 200u128; + + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(UsdtLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(UsdtLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // Register foreign asset (USDT) with asset id 0 - assert_ok!( as FungibleCerate< + // Register foreign asset (USDT) with asset id 0 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some USDT to ALICE for test - assert_ok!(Assets::mint( + // Mint some USDT to ALICE for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), ALICE, ENDOWED_BALANCE, )); - assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(UsdtLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -1418,67 +1494,67 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE - amount); - // USDT in the mock runtime has been configured as the reserved token, so the corresponding account should hold the deposit balance - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ), - ), - amount - fee - ); - assert_eq!(Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), fee); - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdtResourceId::get(), - deposit_nonce: 0, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - amount - fee, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdtResourceId::get(), - fee_amount: fee, - fee_asset_id: UsdtLocation::get().into(), - }), - ]); - }) - } - - #[test] - fn deposit_unbounded_asset_should_fail() { - new_test_ext().execute_with(|| { - let unbounded_asset_location = MultiLocation::new(1, X1(GeneralIndex(123))); - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 100u128; - let amount = 200u128; - - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBasicFeeHandler::set_fee( + // Check balances + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE - amount); + // USDT in the mock runtime has been configured as the reserved token, so the corresponding account should hold the deposit balance + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + amount - fee + ); + assert_eq!(Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), fee); + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: UsdtResourceId::get(), + deposit_nonce: 0, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + amount - fee, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: UsdtResourceId::get(), + fee_amount: fee, + fee_asset_id: UsdtLocation::get().into(), + }), + ]); + }) + } + + #[test] + fn deposit_unbounded_asset_should_fail() { + new_test_ext().execute_with(|| { + let unbounded_asset_location = MultiLocation::new(1, X1(GeneralIndex(123))); + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 100u128; + let amount = 200u128; + + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(unbounded_asset_location.into()), fee )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(unbounded_asset_location), Fungible(amount)).into()), @@ -1492,34 +1568,34 @@ pub mod pallet { ), bridge::Error::::AssetNotBound ); - }) - } - - #[test] - fn deposit_to_unrecognized_dest_should_fail() { - new_test_ext().execute_with(|| { - let invalid_dest = MultiLocation::new( - 0, - X2(GeneralIndex(0), slice_to_generalkey(b"ethereum recipient")), - ); - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 100u128; - let amount = 200u128; + }) + } + + #[test] + fn deposit_to_unrecognized_dest_should_fail() { + new_test_ext().execute_with(|| { + let invalid_dest = MultiLocation::new( + 0, + X2(GeneralIndex(0), slice_to_generalkey(b"ethereum recipient")), + ); + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 100u128; + let amount = 200u128; - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1527,21 +1603,21 @@ pub mod pallet { ), bridge::Error::::ExtractDestDataFailed ); - }) - } + }) + } - #[test] - fn deposit_without_fee_set_should_fail() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let amount = 200u128; - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBridge::register_domain( + #[test] + fn deposit_without_fee_set_should_fail() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let amount = 200u128; + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1555,35 +1631,35 @@ pub mod pallet { ), bridge::Error::::MissingFeeConfig ); - }) - } + }) + } - #[test] - fn deposit_less_than_fee_should_fail() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 200u128; - let amount = 100u128; + #[test] + fn deposit_less_than_fee_should_fail() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 200u128; + let amount = 100u128; - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1597,41 +1673,41 @@ pub mod pallet { ), bridge::Error::::FeeTooExpensive ); - }) - } + }) + } - #[test] - fn deposit_when_bridge_paused_should_fail() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let fee = 100u128; - let amount = 200u128; + #[test] + fn deposit_when_bridge_paused_should_fail() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let fee = 100u128; + let amount = 200u128; - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - // register domain - assert_ok!(SygmaBridge::register_domain( + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // set mpc address will also unpause all bridges - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + // set mpc address will also unpause all bridges + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // Pause bridge again - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - // Should failed - assert_noop!( + // Pause bridge again + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + // Should failed + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1645,10 +1721,10 @@ pub mod pallet { ), bridge::Error::::BridgePaused ); - // Unpause bridge - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - // Should success - assert_ok!(SygmaBridge::deposit( + // Unpause bridge + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + // Should success + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -1659,22 +1735,22 @@ pub mod pallet { ) }), )); - }) - } + }) + } - #[test] - fn deposit_without_mpc_set_should_fail() { - new_test_ext().execute_with(|| { - let fee = 200u128; - let amount = 100u128; + #[test] + fn deposit_without_mpc_set_should_fail() { + new_test_ext().execute_with(|| { + let fee = 200u128; + let amount = 100u128; - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_noop!( + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -1688,101 +1764,101 @@ pub mod pallet { ), bridge::Error::::MissingMpcAddress ); - }) - } - - #[test] - fn retry_bridge() { - new_test_ext().execute_with(|| { - // should be access denied SINCE Alice does not have permission to retry - assert_noop!( + }) + } + + #[test] + fn retry_bridge() { + new_test_ext().execute_with(|| { + // should be access denied SINCE Alice does not have permission to retry + assert_noop!( SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - // Grant ALICE the access of `retry` - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access of `retry` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"retry".to_vec(), ALICE )); - // mpc address is missing, should fail - assert_noop!( + // mpc address is missing, should fail + assert_noop!( SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID), bridge::Error::::MissingMpcAddress ); - // set mpc address - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_ok!(SygmaBridge::register_domain( + // set mpc address + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // pause bridge after set mpc address and retry, should fail - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert_noop!( + // pause bridge after set mpc address and retry, should fail + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert_noop!( SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID), bridge::Error::::BridgePaused ); - // unpause bridge - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(!IsPaused::::get(DEST_DOMAIN_ID)); - - // retry again, should work - assert_ok!(SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Retry { - deposit_on_block_height: 1234567u128, - dest_domain_id: DEST_DOMAIN_ID, - sender: ALICE, - })]); - }) - } - - #[test] - fn proposal_execution_should_work() { - new_test_ext().execute_with(|| { - // mpc address is missing, should fail - assert_noop!( + // unpause bridge + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(!IsPaused::::get(DEST_DOMAIN_ID)); + + // retry again, should work + assert_ok!(SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Retry { + deposit_on_block_height: 1234567u128, + dest_domain_id: DEST_DOMAIN_ID, + sender: ALICE, + })]); + }) + } + + #[test] + fn proposal_execution_should_work() { + new_test_ext().execute_with(|| { + // mpc address is missing, should fail + assert_noop!( SygmaBridge::execute_proposal(Origin::signed(ALICE), vec![], vec![]), bridge::Error::::MissingMpcAddress, ); - // set mpc address to generated keypair's address - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_eq!(MpcAddr::::get(), test_mpc_addr); - // register domain - assert_ok!(SygmaBridge::register_domain( + // set mpc address to generated keypair's address + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_eq!(MpcAddr::::get(), test_mpc_addr); + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // Generate an evil key - let (evil_pair, _): (ecdsa::Pair, _) = Pair::generate(); + // Generate an evil key + let (evil_pair, _): (ecdsa::Pair, _) = Pair::generate(); - // Deposit some native asset in advance - let fee = 1_000_000_000_000u128; - let amount: u128 = 200_000_000_000_000u128; - assert_ok!(SygmaBasicFeeHandler::set_fee( + // Deposit some native asset in advance + let fee = 1_000_000_000_000u128; + let amount: u128 = 200_000_000_000_000u128; + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -1794,13 +1870,13 @@ pub mod pallet { }), )); - // Register foreign asset (USDT) with asset id 0 - assert_ok!( as FungibleCerate< + // Register foreign asset (USDT) with asset id 0 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint 400 USDT to liquidity holder for test - assert_ok!(Assets::mint( + // Mint 400 USDT to liquidity holder for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), AccountId::new( @@ -1809,127 +1885,127 @@ pub mod pallet { ), 400_000_000_000_000, )); - // alice deposit 200 - 1 token fee native token, so the native token holder should have 199 tokens - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 199_000_000_000_000 - ); - // USDT liquidity holder should have 400 USDT at this moment - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ), - ), - 400_000_000_000_000 - ); - - // Generate proposals - // amount is in 18 decimal 0.000200000000000000, will be convert to 12 decimal - // 0.000200000000 - let valid_native_transfer_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 1, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - // amount is in 18 decimal 0.000200000000000000, will be convert to 18 decimal - // 0.000200000000000000 - let valid_usdt_transfer_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 2, - resource_id: UsdtResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let invalid_depositnonce_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 2, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let invalid_domainid_proposal = Proposal { - origin_domain_id: 2, - deposit_nonce: 3, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let invalid_resourceid_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 3, - resource_id: [2u8; 32], - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let invalid_recipient_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 3, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data(amount, b"invalid recipient".to_vec()), - }; - let empty_data_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 3, - resource_id: UsdtResourceId::get(), - data: vec![], - }; - - let proposals = vec![ - valid_native_transfer_proposal, - valid_usdt_transfer_proposal, - invalid_depositnonce_proposal, - invalid_domainid_proposal, - invalid_resourceid_proposal, - invalid_recipient_proposal, - empty_data_proposal, - ]; - - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - let proposals_with_valid_signature = pair.sign_prehashed(&final_message); - let proposals_with_bad_signature = evil_pair.sign_prehashed(&final_message); - - // Should failed if dest domain 1 bridge paused - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(IsPaused::::get(DEST_DOMAIN_ID)); - assert_ok!(SygmaBridge::execute_proposal( + // alice deposit 200 - 1 token fee native token, so the native token holder should have 199 tokens + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 199_000_000_000_000 + ); + // USDT liquidity holder should have 400 USDT at this moment + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + 400_000_000_000_000 + ); + + // Generate proposals + // amount is in 18 decimal 0.000200000000000000, will be convert to 12 decimal + // 0.000200000000 + let valid_native_transfer_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 1, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + // amount is in 18 decimal 0.000200000000000000, will be convert to 18 decimal + // 0.000200000000000000 + let valid_usdt_transfer_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 2, + resource_id: UsdtResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let invalid_depositnonce_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 2, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let invalid_domainid_proposal = Proposal { + origin_domain_id: 2, + deposit_nonce: 3, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let invalid_resourceid_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 3, + resource_id: [2u8; 32], + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let invalid_recipient_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 3, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data(amount, b"invalid recipient".to_vec()), + }; + let empty_data_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 3, + resource_id: UsdtResourceId::get(), + data: vec![], + }; + + let proposals = vec![ + valid_native_transfer_proposal, + valid_usdt_transfer_proposal, + invalid_depositnonce_proposal, + invalid_domainid_proposal, + invalid_resourceid_proposal, + invalid_recipient_proposal, + empty_data_proposal, + ]; + + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + let proposals_with_valid_signature = pair.sign_prehashed(&final_message); + let proposals_with_bad_signature = evil_pair.sign_prehashed(&final_message); + + // Should failed if dest domain 1 bridge paused + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(IsPaused::::get(DEST_DOMAIN_ID)); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals.clone(), proposals_with_valid_signature.encode() )); - // should emit FailedHandlerExecution event - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::FailedHandlerExecution { - error: vec![66, 114, 105, 100, 103, 101, 80, 97, 117, 115, 101, 100], - origin_domain_id: 1, - deposit_nonce: 3, - }, - )]); - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - - assert_noop!( + // should emit FailedHandlerExecution event + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::FailedHandlerExecution { + error: vec![66, 114, 105, 100, 103, 101, 80, 97, 117, 115, 101, 100], + origin_domain_id: 1, + deposit_nonce: 3, + }, + )]); + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + + assert_noop!( SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals.clone(), @@ -1937,294 +2013,294 @@ pub mod pallet { ), bridge::Error::::BadMpcSignature, ); - assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE); - assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), 0); - assert!(SygmaBridge::verify_by_mpc_address( - final_message, - proposals_with_valid_signature.encode(), - )); - assert_ok!(SygmaBridge::execute_proposal( + assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE); + assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), 0); + assert!(SygmaBridge::verify_by_mpc_address( + final_message, + proposals_with_valid_signature.encode(), + )); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals, proposals_with_valid_signature.encode(), )); - // proposal amount is in 18 decimal 0.000200000000000000, will be convert to 12 - // decimal 0.000200000000(200000000) because native asset is defined in 12 decimal - assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE + 200000000); - // usdt is defined in 18 decimal so that converted amount is the same as in proposal - assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), amount); - - // liquidity holder accounts balance after proposals execution - // 199 - 0.0002 native token is 198.999800000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 199_000_000_000_000 - 200_000_000 - ); - // 400 USDT after transferring out the USDT proposal, should remain 200 USDT - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ), - ), - 200_000_000_000_000 - ); - }) - } - - #[test] - fn get_bridge_pause_status() { - new_test_ext().execute_with(|| { - assert!(!SygmaBridge::is_paused(DEST_DOMAIN_ID)); - - // set mpc address - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // register domain - assert_ok!(SygmaBridge::register_domain( + // proposal amount is in 18 decimal 0.000200000000000000, will be convert to 12 + // decimal 0.000200000000(200000000) because native asset is defined in 12 decimal + assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE + 200000000); + // usdt is defined in 18 decimal so that converted amount is the same as in proposal + assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), amount); + + // liquidity holder accounts balance after proposals execution + // 199 - 0.0002 native token is 198.999800000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 199_000_000_000_000 - 200_000_000 + ); + // 400 USDT after transferring out the USDT proposal, should remain 200 USDT + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + 200_000_000_000_000 + ); + }) + } + + #[test] + fn get_bridge_pause_status() { + new_test_ext().execute_with(|| { + assert!(!SygmaBridge::is_paused(DEST_DOMAIN_ID)); + + // set mpc address + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // pause bridge - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(SygmaBridge::is_paused(DEST_DOMAIN_ID)); + // pause bridge + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(SygmaBridge::is_paused(DEST_DOMAIN_ID)); - // unpause bridge - assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); - assert!(!SygmaBridge::is_paused(DEST_DOMAIN_ID)); - }) - } + // unpause bridge + assert_ok!(SygmaBridge::unpause_bridge(Origin::root(), DEST_DOMAIN_ID)); + assert!(!SygmaBridge::is_paused(DEST_DOMAIN_ID)); + }) + } - #[test] - fn access_control() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + #[test] + fn access_control() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_noop!( + assert_noop!( SygmaBridge::set_mpc_address(Some(ALICE).into(), test_mpc_addr), bridge::Error::::AccessDenied ); - assert_noop!( + assert_noop!( SygmaBridge::pause_bridge(Some(BOB).into(), DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - assert_noop!( + assert_noop!( SygmaBridge::unpause_bridge(Some(BOB).into(), DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - // Grant ALICE the access of `set_mpc_address` - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access of `set_mpc_address` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"set_mpc_address".to_vec(), ALICE )); - // Grant BOB the access of `pause_bridge` and `unpause_bridge` - assert_ok!(AccessSegregator::grant_access( + // Grant BOB the access of `pause_bridge` and `unpause_bridge` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"pause_bridge".to_vec(), BOB )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unpause_bridge".to_vec(), BOB )); - // BOB set mpc address should still failed - assert_noop!( + // BOB set mpc address should still failed + assert_noop!( SygmaBridge::set_mpc_address(Some(BOB).into(), test_mpc_addr), bridge::Error::::AccessDenied ); - // ALICE set mpc address should work - assert_ok!(SygmaBridge::set_mpc_address(Some(ALICE).into(), test_mpc_addr)); - // register domain - assert_ok!(SygmaBridge::register_domain( + // ALICE set mpc address should work + assert_ok!(SygmaBridge::set_mpc_address(Some(ALICE).into(), test_mpc_addr)); + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // ALICE pause&unpause bridge should still failed - assert_noop!( + // ALICE pause&unpause bridge should still failed + assert_noop!( SygmaBridge::pause_bridge(Some(ALICE).into(), DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - assert_noop!( + assert_noop!( SygmaBridge::unpause_bridge(Some(ALICE).into(), DEST_DOMAIN_ID), bridge::Error::::AccessDenied ); - // BOB pause&unpause bridge should work - assert_ok!(SygmaBridge::pause_bridge(Some(BOB).into(), DEST_DOMAIN_ID)); - assert_ok!(SygmaBridge::unpause_bridge(Some(BOB).into(), DEST_DOMAIN_ID)); - }) - } - - #[test] - fn multi_domain_test() { - new_test_ext().execute_with(|| { - // root register domainID 1 with chainID 0, should be ok - assert_ok!(SygmaBridge::register_domain(Origin::root(), 1u8, U256::from(0))); - - // set mpc address - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - - // alice register domainID 1 with chainID 1, should raise error AccessDenied - assert_noop!( + // BOB pause&unpause bridge should work + assert_ok!(SygmaBridge::pause_bridge(Some(BOB).into(), DEST_DOMAIN_ID)); + assert_ok!(SygmaBridge::unpause_bridge(Some(BOB).into(), DEST_DOMAIN_ID)); + }) + } + + #[test] + fn multi_domain_test() { + new_test_ext().execute_with(|| { + // root register domainID 1 with chainID 0, should be ok + assert_ok!(SygmaBridge::register_domain(Origin::root(), 1u8, U256::from(0))); + + // set mpc address + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + + // alice register domainID 1 with chainID 1, should raise error AccessDenied + assert_noop!( SygmaBridge::register_domain(Origin::from(Some(ALICE)), 1u8, U256::from(1)), Error::::AccessDenied ); - // Grant ALICE the access of `register_domain` - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access of `register_domain` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"register_domain".to_vec(), ALICE )); - // alice register domainID 1 with chainID 1, should be ok - assert_ok!(SygmaBridge::register_domain( + // alice register domainID 1 with chainID 1, should be ok + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), 1u8, U256::from(1) )); - // should emit RegisterDestDomain event - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::RegisterDestDomain { - sender: ALICE, - domain_id: 1, - chain_id: U256::from(1), - }, - )]); - // storage check - assert!(DestDomainIds::::get(1u8)); - assert_eq!(DestChainIds::::get(1u8).unwrap(), U256::from(1)); - - // alice unregister domainID 1 with chainID 0, should raise error AccessDenied - assert_noop!( + // should emit RegisterDestDomain event + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::RegisterDestDomain { + sender: ALICE, + domain_id: 1, + chain_id: U256::from(1), + }, + )]); + // storage check + assert!(DestDomainIds::::get(1u8)); + assert_eq!(DestChainIds::::get(1u8).unwrap(), U256::from(1)); + + // alice unregister domainID 1 with chainID 0, should raise error AccessDenied + assert_noop!( SygmaBridge::unregister_domain(Origin::from(Some(ALICE)), 1u8, U256::from(0)), Error::::AccessDenied ); - // Grant ALICE the access of `unregister_domain` - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access of `unregister_domain` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unregister_domain".to_vec(), ALICE )); - // alice unregister domainID 1 with chainID 2, should raise error - // DestChainIDNotMatch - assert_noop!( + // alice unregister domainID 1 with chainID 2, should raise error + // DestChainIDNotMatch + assert_noop!( SygmaBridge::unregister_domain(Origin::from(Some(ALICE)), 1u8, U256::from(2)), Error::::DestChainIDNotMatch ); - // alice unregister domainID 2 with chainID 2, should raise error - // DestDomainNotSupported - assert_noop!( + // alice unregister domainID 2 with chainID 2, should raise error + // DestDomainNotSupported + assert_noop!( SygmaBridge::unregister_domain(Origin::from(Some(ALICE)), 2u8, U256::from(2)), Error::::DestDomainNotSupported ); - // alice unregister domainID 1 with chainID 1, should success - assert_ok!(SygmaBridge::unregister_domain( + // alice unregister domainID 1 with chainID 1, should success + assert_ok!(SygmaBridge::unregister_domain( Origin::from(Some(ALICE)), 1u8, U256::from(1) )); - // should emit UnregisterDestDomain event - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::UnregisterDestDomain { - sender: ALICE, - domain_id: 1, - chain_id: U256::from(1), - }, - )]); - - // storage check - // DomainID 1 should not support anymore - assert!(!DestDomainIds::::get(1u8)); - // corresponding chainID should be None since kv not exist anymore - assert!(DestChainIds::::get(1u8).is_none()); - }) - } - - #[test] - fn deposit_with_decimal_converter() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - - // native asset with 12 decimal - let fee_native_asset = 1_000_000_000_000u128; // 1.0 native asset - let amount_native_asset = 123_456_789_123_456u128; // 123.456_789_123_456 - let adjusted_amount_native_asset = 122_456_789_123_456_000_000u128; // amount_native_asset - fee_native_asset then adjust it to 18 decimals - - // usdt asset with 18 decimal - let fee_usdt_asset = 1_000_000_000_000_000_000u128; // 1.0 usdt asset - let amount_usdt_asset = 123_456_789_123_456_789_123u128; // 123.456_789_123_456_789_123 - let adjusted_amount_usdt_asset = 122_456_789_123_456_789_123u128; // amount_usdt_asset - fee_usdt_asset then adjust it to 18 decimals - - // astr asset with 24 decimal - let fee_astr_asset = 1_000_000_000_000_000_000_000_000u128; // 1.0 astr asset - let amount_astr_asset = 123_456_789_123_456_789_123_456_789u128; // 123.456_789_123_456_789_123_456_789 - let adjusted_amount_astr_asset = 122_456_789_123_456_789_123u128; // amount_astr_asset - fee_astr_asset then adjust it to 18 decimals - - // set fees - assert_ok!(SygmaBasicFeeHandler::set_fee( + // should emit UnregisterDestDomain event + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::UnregisterDestDomain { + sender: ALICE, + domain_id: 1, + chain_id: U256::from(1), + }, + )]); + + // storage check + // DomainID 1 should not support anymore + assert!(!DestDomainIds::::get(1u8)); + // corresponding chainID should be None since kv not exist anymore + assert!(DestChainIds::::get(1u8).is_none()); + }) + } + + #[test] + fn deposit_with_decimal_converter() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + + // native asset with 12 decimal + let fee_native_asset = 1_000_000_000_000u128; // 1.0 native asset + let amount_native_asset = 123_456_789_123_456u128; // 123.456_789_123_456 + let adjusted_amount_native_asset = 122_456_789_123_456_000_000u128; // amount_native_asset - fee_native_asset then adjust it to 18 decimals + + // usdt asset with 18 decimal + let fee_usdt_asset = 1_000_000_000_000_000_000u128; // 1.0 usdt asset + let amount_usdt_asset = 123_456_789_123_456_789_123u128; // 123.456_789_123_456_789_123 + let adjusted_amount_usdt_asset = 122_456_789_123_456_789_123u128; // amount_usdt_asset - fee_usdt_asset then adjust it to 18 decimals + + // astr asset with 24 decimal + let fee_astr_asset = 1_000_000_000_000_000_000_000_000u128; // 1.0 astr asset + let amount_astr_asset = 123_456_789_123_456_789_123_456_789u128; // 123.456_789_123_456_789_123_456_789 + let adjusted_amount_astr_asset = 122_456_789_123_456_789_123u128; // amount_astr_asset - fee_astr_asset then adjust it to 18 decimals + + // set fees + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee_native_asset )); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(UsdtLocation::get().into()), fee_usdt_asset )); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(AstrLocation::get().into()), fee_astr_asset )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(UsdtLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(AstrLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - // deposit native asset which has 12 decimal - assert_ok!(SygmaBridge::deposit( + // deposit native asset which has 12 decimal + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new( (Concrete(NativeLocation::get()), Fungible(amount_native_asset)).into() @@ -2237,58 +2313,58 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount_native_asset); - // native asset should be reserved so that BridgeAccount should hold it - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount_native_asset - fee_native_asset - ); - // TreasuryAccount is collecting the bridging fee - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee_native_asset); - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - deposit_nonce: 0, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - adjusted_amount_native_asset, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - fee_amount: fee_native_asset, - fee_asset_id: NativeLocation::get().into(), - }), - ]); - - // deposit usdt asset which has 18 decimal - // Register foreign asset (usdt) with asset id 0 - assert_ok!( as FungibleCerate< + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount_native_asset); + // native asset should be reserved so that BridgeAccount should hold it + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount_native_asset - fee_native_asset + ); + // TreasuryAccount is collecting the bridging fee + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee_native_asset); + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + deposit_nonce: 0, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + adjusted_amount_native_asset, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + fee_amount: fee_native_asset, + fee_asset_id: NativeLocation::get().into(), + }), + ]); + + // deposit usdt asset which has 18 decimal + // Register foreign asset (usdt) with asset id 0 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some usdt to ALICE for test - assert_ok!(Assets::mint( + // Mint some usdt to ALICE for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), ALICE, ENDOWED_BALANCE, )); // make sure Alice owns enough funds here - assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); - // deposit - assert_ok!(SygmaBridge::deposit( + // deposit + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(UsdtLocation::get()), Fungible(amount_usdt_asset)).into()), Box::new(MultiLocation { @@ -2299,67 +2375,67 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!( - Assets::balance(UsdtAssetId::get(), &ALICE), - ENDOWED_BALANCE - amount_usdt_asset - ); - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ), - ), - 122_456_789_123_456_789_123 - ); - // TreasuryAccount is collecting the bridging fee - assert_eq!( - Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), - fee_usdt_asset - ); - - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdtResourceId::get(), - deposit_nonce: 1, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - adjusted_amount_usdt_asset, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: UsdtResourceId::get(), - fee_amount: fee_usdt_asset, - fee_asset_id: UsdtLocation::get().into(), - }), - ]); - - // deposit astr asset which has 24 decimal - // Register foreign asset (astr) with asset id 1 - assert_ok!( as FungibleCerate< + // Check balances + assert_eq!( + Assets::balance(UsdtAssetId::get(), &ALICE), + ENDOWED_BALANCE - amount_usdt_asset + ); + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + 122_456_789_123_456_789_123 + ); + // TreasuryAccount is collecting the bridging fee + assert_eq!( + Assets::balance(UsdtAssetId::get(), TreasuryAccount::get()), + fee_usdt_asset + ); + + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: UsdtResourceId::get(), + deposit_nonce: 1, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + adjusted_amount_usdt_asset, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: UsdtResourceId::get(), + fee_amount: fee_usdt_asset, + fee_asset_id: UsdtLocation::get().into(), + }), + ]); + + // deposit astr asset which has 24 decimal + // Register foreign asset (astr) with asset id 1 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(AstrAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some astr to ALICE for test - assert_ok!(Assets::mint( + // Mint some astr to ALICE for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(1), ALICE, ENDOWED_BALANCE, )); // make sure Alice owns enough funds here - assert_eq!(Assets::balance(AstrAssetId::get(), &ALICE), ENDOWED_BALANCE); + assert_eq!(Assets::balance(AstrAssetId::get(), &ALICE), ENDOWED_BALANCE); - // deposit - assert_ok!(SygmaBridge::deposit( + // deposit + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(AstrLocation::get()), Fungible(amount_astr_asset)).into()), Box::new(MultiLocation { @@ -2370,65 +2446,65 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!( - Assets::balance(AstrAssetId::get(), &ALICE), - ENDOWED_BALANCE - amount_astr_asset - ); - // astr asset should be reserved so that BridgeAccount should hold it(Astr is not - // defined in ConcrateSygmaAsset) - assert_eq!( - Assets::balance( - AstrAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) - .unwrap() - ), - ), - amount_astr_asset - fee_astr_asset - ); - // TreasuryAccount is collecting the bridging fee - assert_eq!( - Assets::balance(AstrAssetId::get(), TreasuryAccount::get()), - fee_astr_asset - ); - - // Check event - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: AstrResourceId::get(), - deposit_nonce: 2, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - adjusted_amount_astr_asset, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: AstrResourceId::get(), - fee_amount: fee_astr_asset, - fee_asset_id: AstrLocation::get().into(), - }), - ]); - - // deposit astr asset which has 24 decimal, extreme small amount edge case - let amount_astr_asset_extreme_small_amount = 100_000; // 0.000000000000000000100000 astr - let fee_astr_asset_extreme_small_amount = 1; - // 0.000000000000000000000001 astr - assert_ok!(SygmaBasicFeeHandler::set_fee( + // Check balances + assert_eq!( + Assets::balance(AstrAssetId::get(), &ALICE), + ENDOWED_BALANCE - amount_astr_asset + ); + // astr asset should be reserved so that BridgeAccount should hold it(Astr is not + // defined in ConcrateSygmaAsset) + assert_eq!( + Assets::balance( + AstrAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) + .unwrap() + ), + ), + amount_astr_asset - fee_astr_asset + ); + // TreasuryAccount is collecting the bridging fee + assert_eq!( + Assets::balance(AstrAssetId::get(), TreasuryAccount::get()), + fee_astr_asset + ); + + // Check event + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: AstrResourceId::get(), + deposit_nonce: 2, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + adjusted_amount_astr_asset, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: AstrResourceId::get(), + fee_amount: fee_astr_asset, + fee_asset_id: AstrLocation::get().into(), + }), + ]); + + // deposit astr asset which has 24 decimal, extreme small amount edge case + let amount_astr_asset_extreme_small_amount = 100_000; // 0.000000000000000000100000 astr + let fee_astr_asset_extreme_small_amount = 1; + // 0.000000000000000000000001 astr + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(AstrLocation::get().into()), fee_astr_asset_extreme_small_amount )); - // after decimal conversion from 24 to 18, the final amount will be 0 so that - // decimal conversion will raise error deposit should not work - assert_noop!( + // after decimal conversion from 24 to 18, the final amount will be 0 so that + // decimal conversion will raise error deposit should not work + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new( @@ -2448,42 +2524,42 @@ pub mod pallet { ), bridge::Error::::DecimalConversionFail ); - }) - } - - #[test] - fn proposal_execution_with_decimal_converter() { - new_test_ext().execute_with(|| { - // generate mpc keypair - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); - // set mpc address - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // register domain - assert_ok!(SygmaBridge::register_domain( + }) + } + + #[test] + fn proposal_execution_with_decimal_converter() { + new_test_ext().execute_with(|| { + // generate mpc keypair + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); + // set mpc address + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + // register domain + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - let fee = 1_000_000_000_000u128; // 1 token in 12 decimals - let init_deposit = 10_000_000_000_000u128; - // 12 token in 12 decimal - assert_ok!(SygmaBasicFeeHandler::set_fee( + let fee = 1_000_000_000_000u128; // 1 token in 12 decimals + let init_deposit = 10_000_000_000_000u128; + // 12 token in 12 decimal + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - // deposit in advance to make sure the native asset has enough funds in - // TransferReserveAccount by doing this, Alice will deposit (half of her native - // asset - fee) into TransferReserveAccount - assert_ok!(SygmaBridge::deposit( + // deposit in advance to make sure the native asset has enough funds in + // TransferReserveAccount by doing this, Alice will deposit (half of her native + // asset - fee) into TransferReserveAccount + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new( (Concrete(NativeLocation::get()), Fungible(ENDOWED_BALANCE / 2)).into() @@ -2496,57 +2572,57 @@ pub mod pallet { ) }), )); - // BridgeAccount should have half of alice native asset - fee - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - ENDOWED_BALANCE / 2 - fee - ); - // TreasuryAccount is collecting the bridging fee - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); - - let bridge_amount = 100_000_000_000_000_000_000; // 100 native with 18 decimals - - // proposal for bridging native asset to alice(native asset is 12 decimal) - let p_native = Proposal { - origin_domain_id: 1, - resource_id: NativeResourceId::get(), - deposit_nonce: 1, - data: SygmaBridge::create_deposit_data( - bridge_amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) - .encode(), - ), - }; - let proposals = vec![p_native]; - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - let signature = pair.sign_prehashed(&final_message); - - // check Alice balance of native asset before executing, should have half of the - // init native asset - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE / 2); - assert_ok!(SygmaBridge::execute_proposal( + // BridgeAccount should have half of alice native asset - fee + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + ENDOWED_BALANCE / 2 - fee + ); + // TreasuryAccount is collecting the bridging fee + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); + + let bridge_amount = 100_000_000_000_000_000_000; // 100 native with 18 decimals + + // proposal for bridging native asset to alice(native asset is 12 decimal) + let p_native = Proposal { + origin_domain_id: 1, + resource_id: NativeResourceId::get(), + deposit_nonce: 1, + data: SygmaBridge::create_deposit_data( + bridge_amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) + .encode(), + ), + }; + let proposals = vec![p_native]; + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + let signature = pair.sign_prehashed(&final_message); + + // check Alice balance of native asset before executing, should have half of the + // init native asset + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE / 2); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals, signature.encode() )); - // check Alice balance of native asset after executing, should have half of the init - // native asset + 100_000_000_000_000(12 decimal) - assert_eq!( - Balances::free_balance(ALICE), - ENDOWED_BALANCE / 2 + 100_000_000_000_000 - ); + // check Alice balance of native asset after executing, should have half of the init + // native asset + 100_000_000_000_000(12 decimal) + assert_eq!( + Balances::free_balance(ALICE), + ENDOWED_BALANCE / 2 + 100_000_000_000_000 + ); - // proposal for bridging usdt asset to alice(usdt asset is 18 decimal) - // Register foreign asset (usdt) with asset id 0 - assert_ok!( as FungibleCerate< + // proposal for bridging usdt asset to alice(usdt asset is 18 decimal) + // Register foreign asset (usdt) with asset id 0 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some USDT to liquidity holder for test - assert_ok!(Assets::mint( + // Mint some USDT to liquidity holder for test + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(0), AccountId::new( @@ -2555,53 +2631,53 @@ pub mod pallet { ), ENDOWED_BALANCE, )); - assert_eq!( - Assets::balance( - UsdtAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) - .unwrap() - ), - ), - ENDOWED_BALANCE - ); - - let p_usdt = Proposal { - origin_domain_id: 1, - deposit_nonce: 2, - resource_id: UsdtResourceId::get(), - data: SygmaBridge::create_deposit_data( - bridge_amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) - .encode(), - ), - }; - let proposals_usdt = vec![p_usdt]; - let final_message_usdt = - SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_usdt); - let signature_usdt = pair.sign_prehashed(&final_message_usdt); - - // alice does not have any usdt at this moment - assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), 0); - assert_ok!(SygmaBridge::execute_proposal( + assert_eq!( + Assets::balance( + UsdtAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) + .unwrap() + ), + ), + ENDOWED_BALANCE + ); + + let p_usdt = Proposal { + origin_domain_id: 1, + deposit_nonce: 2, + resource_id: UsdtResourceId::get(), + data: SygmaBridge::create_deposit_data( + bridge_amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) + .encode(), + ), + }; + let proposals_usdt = vec![p_usdt]; + let final_message_usdt = + SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_usdt); + let signature_usdt = pair.sign_prehashed(&final_message_usdt); + + // alice does not have any usdt at this moment + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), 0); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals_usdt, signature_usdt.encode() )); - // alice should have 100 usdt at this moment (100 usdt with 18 decimals) - assert_eq!( - Assets::balance(UsdtAssetId::get(), &ALICE), - 100_000_000_000_000_000_000 - ); + // alice should have 100 usdt at this moment (100 usdt with 18 decimals) + assert_eq!( + Assets::balance(UsdtAssetId::get(), &ALICE), + 100_000_000_000_000_000_000 + ); - // proposal for bridging astr asset to alice(astr asset is 24 decimal) - // Register foreign asset (astr) with asset id 1 - assert_ok!( as FungibleCerate< + // proposal for bridging astr asset to alice(astr asset is 24 decimal) + // Register foreign asset (astr) with asset id 1 + assert_ok!( as FungibleCerate< ::AccountId, >>::create(AstrAssetId::get(), ASSET_OWNER, true, 1,)); - // Mint some astr to BridgeAccount for test because astr is reserved asset for - // testing - assert_ok!(Assets::mint( + // Mint some astr to BridgeAccount for test because astr is reserved asset for + // testing + assert_ok!(Assets::mint( Origin::signed(ASSET_OWNER), codec::Compact(1), AccountId::new( @@ -2610,208 +2686,208 @@ pub mod pallet { ), ENDOWED_BALANCE )); - assert_eq!( - Assets::balance( - AstrAssetId::get(), - AccountId::new( - SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) - .unwrap() - ), - ), - ENDOWED_BALANCE - ); - - let p_astr = Proposal { - origin_domain_id: 1, - deposit_nonce: 3, - resource_id: AstrResourceId::get(), - data: SygmaBridge::create_deposit_data( - bridge_amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) - .encode(), - ), - }; - let proposals_astr = vec![p_astr]; - let final_message_astr = - SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_astr); - let signature_astr = pair.sign_prehashed(&final_message_astr); - - // alice does not have any astr at this moment - assert_eq!(Assets::balance(AstrAssetId::get(), &ALICE), 0); - assert_ok!(SygmaBridge::execute_proposal( + assert_eq!( + Assets::balance( + AstrAssetId::get(), + AccountId::new( + SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) + .unwrap() + ), + ), + ENDOWED_BALANCE + ); + + let p_astr = Proposal { + origin_domain_id: 1, + deposit_nonce: 3, + resource_id: AstrResourceId::get(), + data: SygmaBridge::create_deposit_data( + bridge_amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) + .encode(), + ), + }; + let proposals_astr = vec![p_astr]; + let final_message_astr = + SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_astr); + let signature_astr = pair.sign_prehashed(&final_message_astr); + + // alice does not have any astr at this moment + assert_eq!(Assets::balance(AstrAssetId::get(), &ALICE), 0); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals_astr, signature_astr.encode() )); - // alice should have 100 astr at this moment (100 astr with 24 decimals) - assert_eq!( - Assets::balance(AstrAssetId::get(), &ALICE), - 100_000_000_000_000_000_000_000_000 - ); - - // extreme small amount edge case - let extreme_small_bridge_amount = 100_000; // 0.000000000000100000 native asset with 18 decimals - // proposal for bridging native asset to alice(native asset is 12 decimal) - let p_native_extreme = Proposal { - origin_domain_id: 1, - resource_id: NativeResourceId::get(), - deposit_nonce: 4, - data: SygmaBridge::create_deposit_data( - extreme_small_bridge_amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) - .encode(), - ), - }; - let proposals_extreme = vec![p_native_extreme]; - let final_message_extreme = - SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_extreme); - let signature_extreme = pair.sign_prehashed(&final_message_extreme); - - // execute_proposal extrinsic should work but it will actually failed at decimal - // conversion step because 0.000000000000100000 in 18 decimal converts to 12 decimal - // would be 0.000000000000 which is 0 - assert_ok!(SygmaBridge::execute_proposal( + // alice should have 100 astr at this moment (100 astr with 24 decimals) + assert_eq!( + Assets::balance(AstrAssetId::get(), &ALICE), + 100_000_000_000_000_000_000_000_000 + ); + + // extreme small amount edge case + let extreme_small_bridge_amount = 100_000; // 0.000000000000100000 native asset with 18 decimals + // proposal for bridging native asset to alice(native asset is 12 decimal) + let p_native_extreme = Proposal { + origin_domain_id: 1, + resource_id: NativeResourceId::get(), + deposit_nonce: 4, + data: SygmaBridge::create_deposit_data( + extreme_small_bridge_amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })) + .encode(), + ), + }; + let proposals_extreme = vec![p_native_extreme]; + let final_message_extreme = + SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals_extreme); + let signature_extreme = pair.sign_prehashed(&final_message_extreme); + + // execute_proposal extrinsic should work but it will actually failed at decimal + // conversion step because 0.000000000000100000 in 18 decimal converts to 12 decimal + // would be 0.000000000000 which is 0 + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals_extreme, signature_extreme.encode() )); - // should emit FailedHandlerExecution event - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::FailedHandlerExecution { - error: vec![ - 68, 101, 99, 105, 109, 97, 108, 67, 111, 110, 118, 101, 114, 115, 105, - 111, 110, 70, 97, 105, 108, - ], - origin_domain_id: 1, - deposit_nonce: 4, - }, - )]); - }) - } - - #[test] - fn unpause_all_domains_test() { - new_test_ext().execute_with(|| { - // Grant ALICE the access of `register_domain` - assert_ok!(AccessSegregator::grant_access( + // should emit FailedHandlerExecution event + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::FailedHandlerExecution { + error: vec![ + 68, 101, 99, 105, 109, 97, 108, 67, 111, 110, 118, 101, 114, 115, 105, + 111, 110, 70, 97, 105, 108, + ], + origin_domain_id: 1, + deposit_nonce: 4, + }, + )]); + }) + } + + #[test] + fn unpause_all_domains_test() { + new_test_ext().execute_with(|| { + // Grant ALICE the access of `register_domain` + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"register_domain".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"pause_bridge".to_vec(), ALICE )); - // alice register some domains - assert_ok!(SygmaBridge::register_domain( + // alice register some domains + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), 1u8, U256::from(1) )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), 2u8, U256::from(2) )); - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), 3u8, U256::from(3) )); - // pause all - assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 1)); - assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 2)); - assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 3)); + // pause all + assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 1)); + assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 2)); + assert_ok!(SygmaBridge::pause_bridge(Some(ALICE).into(), 3)); - // double check if they are all paused - assert!(SygmaBridge::is_paused(1)); - assert!(SygmaBridge::is_paused(2)); - assert!(SygmaBridge::is_paused(3)); + // double check if they are all paused + assert!(SygmaBridge::is_paused(1)); + assert!(SygmaBridge::is_paused(2)); + assert!(SygmaBridge::is_paused(3)); - SygmaBridge::unpause_all_domains(); + SygmaBridge::unpause_all_domains(); - // all domains should be unpaused now - assert!(!SygmaBridge::is_paused(1)); - assert!(!SygmaBridge::is_paused(2)); - assert!(!SygmaBridge::is_paused(3)); - }) - } + // all domains should be unpaused now + assert!(!SygmaBridge::is_paused(1)); + assert!(!SygmaBridge::is_paused(2)); + assert!(!SygmaBridge::is_paused(3)); + }) + } - #[test] - fn setup_order_test() { - new_test_ext().execute_with(|| { - // Make sure mpc address is not set - let default_addr: MpcAddress = MpcAddress::default(); - assert_eq!(MpcAddr::::get(), default_addr); + #[test] + fn setup_order_test() { + new_test_ext().execute_with(|| { + // Make sure mpc address is not set + let default_addr: MpcAddress = MpcAddress::default(); + assert_eq!(MpcAddr::::get(), default_addr); - // Grant ALICE the access admin extrinsics - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access admin extrinsics + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"register_domain".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unregister_domain".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"pause_bridge".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unpause_bridge".to_vec(), ALICE )); - assert_ok!(AccessSegregator::grant_access( + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"retry".to_vec(), ALICE )); - // alice setup bridges without mpc address setup - assert_ok!(SygmaBridge::register_domain( + // alice setup bridges without mpc address setup + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::unregister_domain( + assert_ok!(SygmaBridge::unregister_domain( Origin::from(Some(ALICE)), DEST_DOMAIN_ID, U256::from(1) )); - // register it back - assert_ok!(SygmaBridge::register_domain( + // register it back + assert_ok!(SygmaBridge::register_domain( Origin::from(Some(ALICE)), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::pause_bridge(Origin::from(Some(ALICE)), 1u8)); - assert_ok!(SygmaBridge::unpause_bridge(Origin::from(Some(ALICE)), 1u8)); - // pause domain 2 again to see if mpc address setup will unpause it - assert_ok!(SygmaBridge::pause_bridge(Origin::from(Some(ALICE)), 1u8)); + assert_ok!(SygmaBridge::pause_bridge(Origin::from(Some(ALICE)), 1u8)); + assert_ok!(SygmaBridge::unpause_bridge(Origin::from(Some(ALICE)), 1u8)); + // pause domain 2 again to see if mpc address setup will unpause it + assert_ok!(SygmaBridge::pause_bridge(Origin::from(Some(ALICE)), 1u8)); - // double check if it's paused - assert!(SygmaBridge::is_paused(1)); + // double check if it's paused + assert!(SygmaBridge::is_paused(1)); - // retry should not work here, should raise MissingMpcAddress - assert_noop!( + // retry should not work here, should raise MissingMpcAddress + assert_noop!( SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID), bridge::Error::::MissingMpcAddress ); - // deposit should not work, should raise MissingMpcAddress - assert_noop!( + // deposit should not work, should raise MissingMpcAddress + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(AstrLocation::get()), Fungible(100)).into()), @@ -2825,45 +2901,45 @@ pub mod pallet { ), bridge::Error::::MissingMpcAddress ); - // proposal execution should not work either, should raise MissingMpcAddress - assert_noop!( + // proposal execution should not work either, should raise MissingMpcAddress + assert_noop!( SygmaBridge::execute_proposal(Origin::signed(ALICE), vec![], vec![]), bridge::Error::::MissingMpcAddress, ); - // set mpc address to generated keypair's address - let (pair, _): (ecdsa::Pair, _) = Pair::generate(); - let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - assert_eq!(MpcAddr::::get(), test_mpc_addr); + // set mpc address to generated keypair's address + let (pair, _): (ecdsa::Pair, _) = Pair::generate(); + let test_mpc_addr: MpcAddress = MpcAddress(pair.public().to_eth_address().unwrap()); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_eq!(MpcAddr::::get(), test_mpc_addr); - // double check if it's unpause now - assert!(!SygmaBridge::is_paused(1)); + // double check if it's unpause now + assert!(!SygmaBridge::is_paused(1)); - // retry again, should work - assert_ok!(SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Retry { - deposit_on_block_height: 1234567u128, - dest_domain_id: DEST_DOMAIN_ID, - sender: ALICE, - })]); + // retry again, should work + assert_ok!(SygmaBridge::retry(Origin::signed(ALICE), 1234567u128, DEST_DOMAIN_ID)); + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Retry { + deposit_on_block_height: 1234567u128, + dest_domain_id: DEST_DOMAIN_ID, + sender: ALICE, + })]); - // deposit should work now - let fee = 1_000_000_000_000u128; - let amount = 200_000_000_000_000u128; - assert_ok!(SygmaBasicFeeHandler::set_fee( + // deposit should work now + let fee = 1_000_000_000_000u128; + let amount = 200_000_000_000_000u128; + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -2874,71 +2950,71 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount - fee - ); - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); - - // proposal execution should work - let valid_native_transfer_proposal = Proposal { - origin_domain_id: DEST_DOMAIN_ID, - deposit_nonce: 1, - resource_id: NativeResourceId::get(), - data: SygmaBridge::create_deposit_data( - amount, - MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) - .encode(), - ), - }; - let proposals = vec![valid_native_transfer_proposal]; - let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); - let proposals_with_valid_signature = pair.sign_prehashed(&final_message); - assert_ok!(SygmaBridge::execute_proposal( + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); + + // proposal execution should work + let valid_native_transfer_proposal = Proposal { + origin_domain_id: DEST_DOMAIN_ID, + deposit_nonce: 1, + resource_id: NativeResourceId::get(), + data: SygmaBridge::create_deposit_data( + amount, + MultiLocation::new(0, X1(AccountId32 { network: None, id: BOB.into() })) + .encode(), + ), + }; + let proposals = vec![valid_native_transfer_proposal]; + let final_message = SygmaBridge::construct_ecdsa_signing_proposals_data(&proposals); + let proposals_with_valid_signature = pair.sign_prehashed(&final_message); + assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), proposals, proposals_with_valid_signature.encode(), )); - // check native asset balance - // proposal amount is in 18 decimal 0.000200000000000000, will be convert to 12 - // decimal 0.000200000000(200000000) because native asset is defined in 12 decimal - assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE + 200000000); - }) - } + // check native asset balance + // proposal amount is in 18 decimal 0.000200000000000000, will be convert to 12 + // decimal 0.000200000000(200000000) because native asset is defined in 12 decimal + assert_eq!(Balances::free_balance(&BOB), ENDOWED_BALANCE + 200000000); + }) + } - #[test] - fn deposit_native_asset_with_percentage_fee() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let amount = 200_000_000_000_000u128; // 200 with 12 decimals + #[test] + fn deposit_native_asset_with_percentage_fee() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let amount = 200_000_000_000_000u128; // 200 with 12 decimals - // test cases - let fee_rate_1 = 500u32; // 5% - let fee_rate_2 = 10000u32; // 100% - let fee_rate_3 = 9999u32; // 99.99% - let fee_rate_4 = 0u32; // 0% - let fee_rate_5 = 15000u32; // 150% + // test cases + let fee_rate_1 = 500u32; // 5% + let fee_rate_2 = 10000u32; // 100% + let fee_rate_3 = 9999u32; // 99.99% + let fee_rate_4 = 0u32; // 0% + let fee_rate_5 = 15000u32; // 150% - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::PercentageFeeHandler, )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // test 5% - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + // test 5% + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -2946,7 +3022,7 @@ pub mod pallet { 0u128, 1_000_000_000_000_000u128 )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -2957,45 +3033,45 @@ pub mod pallet { ) }), )); - // Check balances of Alice after deposit 200 native token - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - // Check reserved native token - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 190_000_000_000_000u128 - ); - // Check fee collected - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 10_000_000_000_000u128); - // Check event - let final_amount_in_deposit_event_1 = 190_000_000_000_000_000_000; // 200 cut 5% then adjust to 18 decimals - assert_events(vec![ - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - deposit_nonce: 0, - sender: ALICE, - transfer_type: TransferType::FungibleTransfer, - deposit_data: SygmaBridge::create_deposit_data( - final_amount_in_deposit_event_1, - b"ethereum recipient".to_vec(), - ), - handler_response: vec![], - }), - RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { - fee_payer: ALICE, - dest_domain_id: DEST_DOMAIN_ID, - resource_id: NativeResourceId::get(), - fee_amount: 10_000_000_000_000u128, - fee_asset_id: NativeLocation::get().into(), - }), - ]); - - // test 100% - // should not work because 100% is out of fee rate - assert_noop!( + // Check balances of Alice after deposit 200 native token + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); + // Check reserved native token + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 190_000_000_000_000u128 + ); + // Check fee collected + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 10_000_000_000_000u128); + // Check event + let final_amount_in_deposit_event_1 = 190_000_000_000_000_000_000; // 200 cut 5% then adjust to 18 decimals + assert_events(vec![ + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::Deposit { + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + deposit_nonce: 0, + sender: ALICE, + transfer_type: TransferType::FungibleTransfer, + deposit_data: SygmaBridge::create_deposit_data( + final_amount_in_deposit_event_1, + b"ethereum recipient".to_vec(), + ), + handler_response: vec![], + }), + RuntimeEvent::SygmaBridge(SygmaBridgeEvent::FeeCollected { + fee_payer: ALICE, + dest_domain_id: DEST_DOMAIN_ID, + resource_id: NativeResourceId::get(), + fee_amount: 10_000_000_000_000u128, + fee_asset_id: NativeLocation::get().into(), + }), + ]); + + // test 100% + // should not work because 100% is out of fee rate + assert_noop!( SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, @@ -3007,9 +3083,9 @@ pub mod pallet { sygma_percentage_feehandler::Error::::FeeRateOutOfRange ); - // test 99.99% - // override 5% to 99.99% - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + // test 99.99% + // override 5% to 99.99% + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -3017,7 +3093,7 @@ pub mod pallet { 0u128, 1_000_000_000_000_000u128 )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3028,20 +3104,20 @@ pub mod pallet { ) }), )); - // Check reserved native token, should increase by 0.02 to 190.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 190_020_000_000_000u128 - ); - // Check fee collected, should increase by 199.98 to 209.980000000000 - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); - - // test 0% - // override 99.99% to 0% - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + // Check reserved native token, should increase by 0.02 to 190.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 190_020_000_000_000u128 + ); + // Check fee collected, should increase by 199.98 to 209.980000000000 + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); + + // test 0% + // override 99.99% to 0% + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -3049,7 +3125,7 @@ pub mod pallet { 0u128, 1_000_000_000_000_000u128 )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3060,20 +3136,20 @@ pub mod pallet { ) }), )); - // Check reserved native token, should increase by 200 to 390.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 390_020_000_000_000u128 - ); - // Check fee collected, should increase by 0 to 209.980000000000 - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); - - // test 150% - // should not work because 150% is out of fee rate - assert_noop!( + // Check reserved native token, should increase by 200 to 390.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 390_020_000_000_000u128 + ); + // Check fee collected, should increase by 0 to 209.980000000000 + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); + + // test 150% + // should not work because 150% is out of fee rate + assert_noop!( SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, @@ -3085,22 +3161,22 @@ pub mod pallet { sygma_percentage_feehandler::Error::::FeeRateOutOfRange ); - // Check reserved native token, should remain as 390.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 390_020_000_000_000u128 - ); - // Check fee collected, should remain as 209.980000000000 - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); + // Check reserved native token, should remain as 390.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 390_020_000_000_000u128 + ); + // Check fee collected, should remain as 209.980000000000 + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 209_980_000_000_000u128); - // test fee bound: fee rate 5% - let fee_lower_bound = 100_000_000_000_000u128; // 100 - let fee_upper_bound = 1_000_000_000_000_000u128; - // 1000 - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + // test fee bound: fee rate 5% + let fee_lower_bound = 100_000_000_000_000u128; // 100 + let fee_upper_bound = 1_000_000_000_000_000u128; + // 1000 + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -3109,9 +3185,9 @@ pub mod pallet { fee_upper_bound )); - // with higher fee lower bound - // 5% fee of 200 token should be 10 but fee lower bound is 100, so fee is 100 now - assert_ok!(SygmaBridge::deposit( + // with higher fee lower bound + // 5% fee of 200 token should be 10 but fee lower bound is 100, so fee is 100 now + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3122,21 +3198,21 @@ pub mod pallet { ) }), )); - // Check reserved native token, should increase by 100 to 490.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 490_020_000_000_000u128 - ); - // Check fee collected, should increase by 100 to 309.980000000000 - assert_eq!(Balances::free_balance(TreasuryAccount::get()), 309_980_000_000_000u128); - - // with lower fee upper bound - // 5% fee of 200000 token should be 10000 but fee upper bound is 1000, so fee is - // 1000 now - assert_ok!(SygmaBridge::deposit( + // Check reserved native token, should increase by 100 to 490.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 490_020_000_000_000u128 + ); + // Check fee collected, should increase by 100 to 309.980000000000 + assert_eq!(Balances::free_balance(TreasuryAccount::get()), 309_980_000_000_000u128); + + // with lower fee upper bound + // 5% fee of 200000 token should be 10000 but fee upper bound is 1000, so fee is + // 1000 now + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new( (Concrete(NativeLocation::get()), Fungible(200_000_000_000_000_000)).into() @@ -3149,46 +3225,46 @@ pub mod pallet { ) }), )); - // Check reserved native token, should increase by 199000 to 199490.020000000000 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - 199_490_020_000_000_000u128 - ); - // Check fee collected, should increase by 1000 to 1309.980000000000 - assert_eq!( - Balances::free_balance(TreasuryAccount::get()), - 1_309_980_000_000_000u128 - ); - }) - } - - #[test] - fn percentage_fee_rate_not_set_for_domain_and_asset() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let amount = 200_000_000_000_000u128; // 200 with 12 decimals - - assert_ok!(SygmaBridge::register_domain( + // Check reserved native token, should increase by 199000 to 199490.020000000000 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + 199_490_020_000_000_000u128 + ); + // Check fee collected, should increase by 1000 to 1309.980000000000 + assert_eq!( + Balances::free_balance(TreasuryAccount::get()), + 1_309_980_000_000_000u128 + ); + }) + } + + #[test] + fn percentage_fee_rate_not_set_for_domain_and_asset() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let amount = 200_000_000_000_000u128; // 200 with 12 decimals + + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // only set fee handler but not set fee rate for domain and asset - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + // only set fee handler but not set fee rate for domain and asset + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::PercentageFeeHandler, )); - // deposit should not go through because fee rate is not set in storage, so when - // get_fee, it returns None - assert_noop!( + // deposit should not go through because fee rate is not set in storage, so when + // get_fee, it returns None + assert_noop!( SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), @@ -3202,38 +3278,38 @@ pub mod pallet { ), bridge::Error::::MissingFeeConfig ); - }) - } + }) + } - #[test] - fn deposit_native_asset_with_percentage_fee_override_basic_fee_handler() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let amount = 200_000_000_000_000u128; // 200 with 12 decimals - let fee = 1_000_000_000_000u128; // 1 with 12 decimals + #[test] + fn deposit_native_asset_with_percentage_fee_override_basic_fee_handler() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + let amount = 200_000_000_000_000u128; // 200 with 12 decimals + let fee = 1_000_000_000_000u128; // 1 with 12 decimals - assert_ok!(SygmaBridge::register_domain( + assert_ok!(SygmaBridge::register_domain( Origin::root(), DEST_DOMAIN_ID, U256::from(1) )); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // set fee handler with basic fee handler and fixed fee - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + // set fee handler with basic fee handler and fixed fee + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::BasicFeeHandler, )); - assert_ok!(SygmaBasicFeeHandler::set_fee( + assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), fee )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3244,25 +3320,25 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount - fee - ); - assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + ); + assert_eq!(Balances::free_balance(TreasuryAccount::get()), fee); - // Override Basic fee handler to Percentage fee handler with 5% fee rate - assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( + // Override Basic fee handler to Percentage fee handler with 5% fee rate + assert_ok!(SygmaFeeHandlerRouter::set_fee_handler( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), FeeHandlerType::PercentageFeeHandler, )); - assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( + assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, Box::new(NativeLocation::get().into()), @@ -3271,7 +3347,7 @@ pub mod pallet { 1_000_000_000_000_000u128 )); - assert_ok!(SygmaBridge::deposit( + assert_ok!(SygmaBridge::deposit( Origin::signed(ALICE), Box::new((Concrete(NativeLocation::get()), Fungible(amount)).into()), Box::new(MultiLocation { @@ -3282,161 +3358,161 @@ pub mod pallet { ) }), )); - // Check balances - assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount * 2); - // Check reserved native token, should increase by 190 - assert_eq!( - Balances::free_balance(AccountId::new( - SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) - .unwrap() - )), - amount - fee + 190_000_000_000_000u128 - ); - // Check fee collected, should increase by 10 - assert_eq!( - Balances::free_balance(TreasuryAccount::get()), - fee + 10_000_000_000_000u128 - ); - }) - } - - #[test] - fn pause_all_bridges_test() { - new_test_ext().execute_with(|| { - let domain_1: DomainID = 1; - let domain_2: DomainID = 2; - let domain_3: DomainID = 3; - - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_1, U256::from(1))); - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_2, U256::from(2))); - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_3, U256::from(3))); - - // all registered domains should be unpaused now - assert!(!IsPaused::::get(domain_1)); - assert!(!IsPaused::::get(domain_2)); - assert!(!IsPaused::::get(domain_3)); - - // permission test: unauthorized account should not be able to pause bridge - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // Check balances + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount * 2); + // Check reserved native token, should increase by 190 + assert_eq!( + Balances::free_balance(AccountId::new( + SygmaBridge::get_token_reserved_account(&NativeLocation::get().into()) + .unwrap() + )), + amount - fee + 190_000_000_000_000u128 + ); + // Check fee collected, should increase by 10 + assert_eq!( + Balances::free_balance(TreasuryAccount::get()), + fee + 10_000_000_000_000u128 + ); + }) + } + + #[test] + fn pause_all_bridges_test() { + new_test_ext().execute_with(|| { + let domain_1: DomainID = 1; + let domain_2: DomainID = 2; + let domain_3: DomainID = 3; + + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_1, U256::from(1))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_2, U256::from(2))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_3, U256::from(3))); + + // all registered domains should be unpaused now + assert!(!IsPaused::::get(domain_1)); + assert!(!IsPaused::::get(domain_2)); + assert!(!IsPaused::::get(domain_3)); + + // permission test: unauthorized account should not be able to pause bridge + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::pause_all_bridges(unauthorized_account), bridge::Error::::AccessDenied ); - // Grant ALICE the access - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"pause_all_bridges".to_vec(), ALICE )); - assert_ok!(SygmaBridge::pause_all_bridges(Origin::signed(ALICE))); + assert_ok!(SygmaBridge::pause_all_bridges(Origin::signed(ALICE))); - // all registered domains should be paused now - assert!(IsPaused::::get(domain_1)); - assert!(IsPaused::::get(domain_2)); - assert!(IsPaused::::get(domain_3)); + // all registered domains should be paused now + assert!(IsPaused::::get(domain_1)); + assert!(IsPaused::::get(domain_2)); + assert!(IsPaused::::get(domain_3)); - assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::AllBridgePaused { - sender: ALICE, - })]); - }) - } + assert_events(vec![RuntimeEvent::SygmaBridge(SygmaBridgeEvent::AllBridgePaused { + sender: ALICE, + })]); + }) + } - #[test] - fn unpause_all_bridges_test() { - new_test_ext().execute_with(|| { - let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); + #[test] + fn unpause_all_bridges_test() { + new_test_ext().execute_with(|| { + let test_mpc_addr: MpcAddress = MpcAddress([1u8; 20]); - let domain_1: DomainID = 1; - let domain_2: DomainID = 2; - let domain_3: DomainID = 3; + let domain_1: DomainID = 1; + let domain_2: DomainID = 2; + let domain_3: DomainID = 3; - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_1, U256::from(1))); - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_2, U256::from(2))); - assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_3, U256::from(3))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_1, U256::from(1))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_2, U256::from(2))); + assert_ok!(SygmaBridge::register_domain(Origin::root(), domain_3, U256::from(3))); - // mpc address not setup, should be error - assert_noop!( + // mpc address not setup, should be error + assert_noop!( SygmaBridge::unpause_all_bridges(Origin::root()), bridge::Error::::MissingMpcAddress ); - assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); + assert_ok!(SygmaBridge::set_mpc_address(Origin::root(), test_mpc_addr)); - // permission test: unauthorized account should not be able to pause bridge - let unauthorized_account = Origin::from(Some(ALICE)); - assert_noop!( + // permission test: unauthorized account should not be able to pause bridge + let unauthorized_account = Origin::from(Some(ALICE)); + assert_noop!( SygmaBridge::unpause_all_bridges(unauthorized_account), bridge::Error::::AccessDenied ); - // Grant ALICE the access - assert_ok!(AccessSegregator::grant_access( + // Grant ALICE the access + assert_ok!(AccessSegregator::grant_access( Origin::root(), BridgePalletIndex::get(), b"unpause_all_bridges".to_vec(), ALICE )); - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_1)); - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_2)); - assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_3)); - - // all registered domains should be paused now - assert!(IsPaused::::get(domain_1)); - assert!(IsPaused::::get(domain_2)); - assert!(IsPaused::::get(domain_3)); - - assert_ok!(SygmaBridge::unpause_all_bridges(Origin::signed(ALICE))); - - // all registered domains should be unpaused now - assert!(!IsPaused::::get(domain_1)); - assert!(!IsPaused::::get(domain_2)); - assert!(!IsPaused::::get(domain_3)); - - assert_events(vec![RuntimeEvent::SygmaBridge( - SygmaBridgeEvent::AllBridgeUnpaused { sender: ALICE }, - )]); - }) - } - - #[test] - fn deposit_nonce_fix_should_work() { - new_test_ext().execute_with(|| { - // Nonce from source chain start from 1, set first batch of nonce under [1, 63] - for nonce in 1..64u64 { - SygmaBridge::set_proposal_executed(nonce, 0); - } - // Nonce 0 should not be set - assert!(!SygmaBridge::is_proposal_executed(0, 0)); - // Nonce 1 should be set - assert!(SygmaBridge::is_proposal_executed(1, 0)); - // Nonce 63 should be set - assert!(SygmaBridge::is_proposal_executed(63, 0)); - - // set second batch of nonce under [64, 127] - for nonce in 64..128u64 { - SygmaBridge::set_proposal_executed(nonce, 0); - } - // Nonce 64 should be set - assert!(SygmaBridge::is_proposal_executed(64, 0)); - // Nonce 127 should be set - assert!(SygmaBridge::is_proposal_executed(127, 0)); - // Nonce 128 should not be set - assert!(!SygmaBridge::is_proposal_executed(128, 0)); - - // set future batch of nonce under [256, 300] - for nonce in 256..301u64 { - SygmaBridge::set_proposal_executed(nonce, 0); - } - // Nonce 256 should be set - assert!(SygmaBridge::is_proposal_executed(256, 0)); - // Nonce 300 should be set - assert!(SygmaBridge::is_proposal_executed(300, 0)); - // Nonce 301 should not be set - assert!(!SygmaBridge::is_proposal_executed(301, 0)); - }) - } - } + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_1)); + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_2)); + assert_ok!(SygmaBridge::pause_bridge(Origin::root(), domain_3)); + + // all registered domains should be paused now + assert!(IsPaused::::get(domain_1)); + assert!(IsPaused::::get(domain_2)); + assert!(IsPaused::::get(domain_3)); + + assert_ok!(SygmaBridge::unpause_all_bridges(Origin::signed(ALICE))); + + // all registered domains should be unpaused now + assert!(!IsPaused::::get(domain_1)); + assert!(!IsPaused::::get(domain_2)); + assert!(!IsPaused::::get(domain_3)); + + assert_events(vec![RuntimeEvent::SygmaBridge( + SygmaBridgeEvent::AllBridgeUnpaused { sender: ALICE }, + )]); + }) + } + + #[test] + fn deposit_nonce_fix_should_work() { + new_test_ext().execute_with(|| { + // Nonce from source chain start from 1, set first batch of nonce under [1, 63] + for nonce in 1..64u64 { + SygmaBridge::set_proposal_executed(nonce, 0); + } + // Nonce 0 should not be set + assert!(!SygmaBridge::is_proposal_executed(0, 0)); + // Nonce 1 should be set + assert!(SygmaBridge::is_proposal_executed(1, 0)); + // Nonce 63 should be set + assert!(SygmaBridge::is_proposal_executed(63, 0)); + + // set second batch of nonce under [64, 127] + for nonce in 64..128u64 { + SygmaBridge::set_proposal_executed(nonce, 0); + } + // Nonce 64 should be set + assert!(SygmaBridge::is_proposal_executed(64, 0)); + // Nonce 127 should be set + assert!(SygmaBridge::is_proposal_executed(127, 0)); + // Nonce 128 should not be set + assert!(!SygmaBridge::is_proposal_executed(128, 0)); + + // set future batch of nonce under [256, 300] + for nonce in 256..301u64 { + SygmaBridge::set_proposal_executed(nonce, 0); + } + // Nonce 256 should be set + assert!(SygmaBridge::is_proposal_executed(256, 0)); + // Nonce 300 should be set + assert!(SygmaBridge::is_proposal_executed(300, 0)); + // Nonce 301 should not be set + assert!(!SygmaBridge::is_proposal_executed(301, 0)); + }) + } + } } diff --git a/bridge/src/mock.rs b/bridge/src/mock.rs index fed102cc..871c9c62 100644 --- a/bridge/src/mock.rs +++ b/bridge/src/mock.rs @@ -26,7 +26,10 @@ use sygma_traits::{ VerifyingContractAddress, }; use xcm::latest::{prelude::*, AssetId as XcmAssetId, MultiLocation}; -use xcm_builder::{AccountId32Aliases, CurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, ParentIsPreset, SiblingParachainConvertsVia}; +use xcm_builder::{ + AccountId32Aliases, CurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, ParentIsPreset, + SiblingParachainConvertsVia, +}; use xcm_executor::traits::{Error as ExecutionError, MatchesFungibles}; type Block = frame_system::mocking::MockBlock; @@ -107,7 +110,7 @@ impl pallet_balances::Config for Runtime { parameter_types! { pub const AssetDeposit: Balance = 0; - pub const AssetAccountDeposit: Balance =0; + pub const AssetAccountDeposit: Balance = 0; pub const ApprovalDeposit: Balance = ExistentialDeposit::get(); pub const AssetsStringLimit: u32 = 50; /// Key = 32 bytes, Value = 36 bytes (32+1+1+1+1) diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 03a2f81d..70855f46 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -69,18 +69,22 @@ pub trait AssetTypeIdentifier { } pub trait TransactorForwarder { - fn xcm_transactor_forwarder(sender: [u8; 32], what: MultiAsset, dest: MultiLocation) -> DispatchResult; - fn other_world_transactor_forwarder(sender: [u8; 32], what: MultiAsset, dest: MultiLocation) -> DispatchResult; -} - -pub trait Bridge { - fn transfer( + fn xcm_transactor_forwarder( + sender: [u8; 32], + what: MultiAsset, + dest: MultiLocation, + ) -> DispatchResult; + fn other_world_transactor_forwarder( sender: [u8; 32], - asset: MultiAsset, + what: MultiAsset, dest: MultiLocation, ) -> DispatchResult; } +pub trait Bridge { + fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult; +} + pub trait AssetReserveLocationParser { fn reserved_location(asset: &MultiAsset) -> Option; -} \ No newline at end of file +} diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 193e491d..7ffa3296 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -10,531 +10,530 @@ mod mock; #[frame_support::pallet] pub mod pallet { - use frame_support::{ - dispatch::DispatchResult, - pallet_prelude::*, - traits::StorageVersion, - }; - use sp_runtime::traits::Zero; - use sp_std::{prelude::*, vec}; - use xcm::latest::{MultiLocation, prelude::*, Weight as XCMWeight}; - use xcm_executor::traits::WeightBounds; - - use sygma_traits::{AssetReserveLocationParser, Bridge}; - - const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); - - #[pallet::pallet] - #[pallet::storage_version(STORAGE_VERSION)] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config { - type RuntimeEvent: From> + IsType<::RuntimeEvent>; - - type Weigher: WeightBounds; - - type XcmExecutor: ExecuteXcm; - - type UniversalLocation: Get; - - #[pallet::constant] - type SelfLocation: Get; - - /// Minimum xcm execution fee paid on destination chain. - type MinXcmFee: Get>; - } - - pub enum TransferKind { - /// Transfer self reserve asset. assets reserved by the origin chain - SelfReserveAsset, - /// To reserve location. assets reserved by the dest chain - ToReserve, - /// To non-reserve location. assets not reserved by the dest chain - ToNonReserve, - } - - #[pallet::event] - #[pallet::generate_deposit(pub (super) fn deposit_event)] - pub enum Event { - XCMTransferSend { - asset: MultiAsset, - origin: MultiLocation, - dest: MultiLocation, - }, - } - - #[pallet::error] - pub enum Error { - FailToWeightMessage, - XcmExecutionFailed, - InvalidDestination, - UnknownTransferType, - CannotReanchor, - NoXcmMiNFeeSet, - } - - #[derive(PartialEq, Eq, Clone, Encode, Decode)] - struct XcmObject { - asset: MultiAsset, - fee: MultiAsset, - origin: MultiLocation, - dest: MultiLocation, - recipient: MultiLocation, - weight: XCMWeight, - _unused: PhantomData, - } - - pub trait XcmHandler { - fn transfer_kind(&self) -> Option; - fn create_instructions(&self) -> Result, DispatchError>; - fn execute_instructions(&self, xcm_instructions: &mut Xcm) -> DispatchResult; - } - - impl XcmHandler for XcmObject { - fn transfer_kind(&self) -> Option { - let asset_location = Pallet::::reserved_location(&self.asset.clone())?; - if asset_location == T::SelfLocation::get() { - Some(TransferKind::SelfReserveAsset) - } else if asset_location == self.dest { - Some(TransferKind::ToReserve) - } else { - Some(TransferKind::ToNonReserve) - } - } - - fn create_instructions(&self) -> Result, DispatchError> { - let kind = Self::transfer_kind(self).ok_or(Error::::UnknownTransferType)?; - - let mut assets = MultiAssets::new(); - assets.push(self.asset.clone()); - - let xcm_instructions = match kind { - TransferKind::SelfReserveAsset => Pallet::::transfer_self_reserve_asset(assets, self.fee.clone(), self.dest, self.recipient, WeightLimit::Limited(self.weight))?, - TransferKind::ToReserve => Pallet::::transfer_to_reserve_asset(assets, self.fee.clone(), self.dest, self.recipient, WeightLimit::Limited(self.weight))?, - TransferKind::ToNonReserve => Pallet::::transfer_to_non_reserve_asset( - assets, - self.fee.clone(), - self.dest, - self.dest.clone(), - self.recipient, - WeightLimit::Limited(self.weight), - )?, - }; - - Ok(xcm_instructions) - } - - fn execute_instructions(&self, xcm_instructions: &mut Xcm) -> DispatchResult { - let message_weight = T::Weigher::weight(xcm_instructions).map_err(|()| Error::::FailToWeightMessage)?; - - let hash = xcm_instructions.using_encoded(sp_io::hashing::blake2_256); - - T::XcmExecutor::execute_xcm_in_credit( - self.origin.clone(), - xcm_instructions.clone(), - hash, - message_weight, - message_weight, - ).ensure_complete().map_err(|_| Error::::XcmExecutionFailed)?; - - Ok(()) - } - } - - - impl AssetReserveLocationParser for Pallet { - fn reserved_location(asset: &MultiAsset) -> Option { - match (&asset.id, &asset.fun) { - (Concrete(id), Fungible(_)) => Some(id.clone()), - _ => None, - } - } - } - - pub struct BridgeImpl(PhantomData); - impl Bridge for BridgeImpl { - fn transfer(sender: [u8; 32], - asset: MultiAsset, - dest: MultiLocation) -> DispatchResult { - let origin_location: MultiLocation = Junction::AccountId32 { - network: None, - id: sender, - }.into(); - - let (dest_location, recipient) = - Pallet::::extract_dest(&dest).ok_or(Error::::InvalidDestination)?; - - ensure!( - T::MinXcmFee::get().iter().position(|a| a.0 == asset.id).map(|idx| { - T::MinXcmFee::get()[idx].1 - }).is_some(), + use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::StorageVersion}; + use sp_runtime::traits::Zero; + use sp_std::{prelude::*, vec}; + use xcm::latest::{prelude::*, MultiLocation, Weight as XCMWeight}; + use xcm_executor::traits::WeightBounds; + + use sygma_traits::{AssetReserveLocationParser, Bridge}; + + const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + + #[pallet::pallet] + #[pallet::storage_version(STORAGE_VERSION)] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + type Weigher: WeightBounds; + + type XcmExecutor: ExecuteXcm; + + type UniversalLocation: Get; + + #[pallet::constant] + type SelfLocation: Get; + + /// Minimum xcm execution fee paid on destination chain. + type MinXcmFee: Get>; + } + + pub enum TransferKind { + /// Transfer self reserve asset. assets reserved by the origin chain + SelfReserveAsset, + /// To reserve location. assets reserved by the dest chain + ToReserve, + /// To non-reserve location. assets not reserved by the dest chain + ToNonReserve, + } + + #[pallet::event] + #[pallet::generate_deposit(pub (super) fn deposit_event)] + pub enum Event { + XCMTransferSend { + asset: Box, + origin: Box, + dest: Box, + }, + } + + #[pallet::error] + pub enum Error { + FailToWeightMessage, + XcmExecutionFailed, + InvalidDestination, + UnknownTransferType, + CannotReanchor, + NoXcmMiNFeeSet, + } + + #[derive(PartialEq, Eq, Clone, Encode, Decode)] + struct XcmObject { + asset: MultiAsset, + fee: MultiAsset, + origin: MultiLocation, + dest: MultiLocation, + recipient: MultiLocation, + weight: XCMWeight, + _unused: PhantomData, + } + + pub trait XcmHandler { + fn transfer_kind(&self) -> Option; + fn create_instructions(&self) -> Result, DispatchError>; + fn execute_instructions( + &self, + xcm_instructions: &mut Xcm, + ) -> DispatchResult; + } + + impl XcmHandler for XcmObject { + fn transfer_kind(&self) -> Option { + let asset_location = Pallet::::reserved_location(&self.asset.clone())?; + if asset_location == T::SelfLocation::get() { + Some(TransferKind::SelfReserveAsset) + } else if asset_location == self.dest { + // TODO: parse to dest multilocation, not asset local + Some(TransferKind::ToReserve) + } else { + Some(TransferKind::ToNonReserve) + } + } + + fn create_instructions(&self) -> Result, DispatchError> { + let kind = Self::transfer_kind(self).ok_or(Error::::UnknownTransferType)?; + + let mut assets = MultiAssets::new(); + assets.push(self.asset.clone()); + + let xcm_instructions = match kind { + TransferKind::SelfReserveAsset => Pallet::::transfer_self_reserve_asset( + assets, + self.fee.clone(), + self.dest, + self.recipient, + WeightLimit::Limited(self.weight), + )?, + TransferKind::ToReserve => Pallet::::transfer_to_reserve_asset( + assets, + self.fee.clone(), + self.dest, + self.recipient, + WeightLimit::Limited(self.weight), + )?, + TransferKind::ToNonReserve => Pallet::::transfer_to_non_reserve_asset( + assets, + self.fee.clone(), + self.dest, + self.dest, + self.recipient, + WeightLimit::Limited(self.weight), + )?, + }; + + Ok(xcm_instructions) + } + + fn execute_instructions( + &self, + xcm_instructions: &mut Xcm, + ) -> DispatchResult { + let message_weight = T::Weigher::weight(xcm_instructions) + .map_err(|()| Error::::FailToWeightMessage)?; + + let hash = xcm_instructions.using_encoded(sp_io::hashing::blake2_256); + + T::XcmExecutor::execute_xcm_in_credit( + self.origin, + xcm_instructions.clone(), + hash, + message_weight, + message_weight, + ) + .ensure_complete() + .map_err(|_| Error::::XcmExecutionFailed)?; + + Ok(()) + } + } + + impl AssetReserveLocationParser for Pallet { + fn reserved_location(asset: &MultiAsset) -> Option { + match (&asset.id, &asset.fun) { + (Concrete(id), Fungible(_)) => Some(*id), + _ => None, + } + } + } + + pub struct BridgeImpl(PhantomData); + + impl Bridge for BridgeImpl { + fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult { + let origin_location: MultiLocation = + Junction::AccountId32 { network: None, id: sender }.into(); + + let (dest_location, recipient) = + Pallet::::extract_dest(&dest).ok_or(Error::::InvalidDestination)?; + + ensure!( + T::MinXcmFee::get() + .iter() + .position(|a| a.0 == asset.id) + .map(|idx| { T::MinXcmFee::get()[idx].1 }) + .is_some(), Error::::NoXcmMiNFeeSet ); - let fee_per_asset = T::MinXcmFee::get().iter().position(|a| a.0 == asset.id).map(|idx| { - T::MinXcmFee::get()[idx].1 - }).unwrap(); - - let fee_to_dest: MultiAsset = (asset.id, fee_per_asset).into(); - - let xcm = XcmObject:: { - asset: asset.clone(), - fee: fee_to_dest, - origin: origin_location.clone(), - dest: dest_location, - recipient, - weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), - _unused: PhantomData, - }; - - let mut msg = xcm.create_instructions()?; - xcm.execute_instructions(&mut msg)?; - - Pallet::::deposit_event(Event::XCMTransferSend { - asset, - origin: origin_location, - dest, - }); - - Ok(()) - } - } - - impl Pallet { - /// extract the dest_location, recipient_location - pub fn extract_dest(dest: &MultiLocation) -> Option<(MultiLocation, MultiLocation)> { - match (dest.parents, dest.first_interior()) { - (1, Some(Parachain(id))) => Some(( - MultiLocation::new(1, X1(Parachain(*id))), - MultiLocation::new(0, dest.interior().clone().split_first().0), - )), - // parent: relay chain - (1, _) => Some(( - MultiLocation::parent(), - MultiLocation::new(0, dest.interior().clone()), - )), - // local and children parachain have been filtered out in the TransactAsset - _ => None, - } - } - fn transfer_self_reserve_asset( - assets: MultiAssets, - fee: MultiAsset, - dest: MultiLocation, - recipient: MultiLocation, - dest_weight_limit: WeightLimit, - ) -> Result, DispatchError> { - Ok(Xcm(vec![TransferReserveAsset { - assets: assets.clone(), - dest, - xcm: Xcm(vec![ - Self::buy_execution(fee, &dest, dest_weight_limit)?, - Self::deposit_asset(recipient, assets.len() as u32), - ]), - }])) - } - - fn transfer_to_reserve_asset( - assets: MultiAssets, - fee: MultiAsset, - reserve: MultiLocation, - recipient: MultiLocation, - dest_weight_limit: WeightLimit, - ) -> Result, DispatchError> { - Ok(Xcm(vec![ - WithdrawAsset(assets.clone()), - InitiateReserveWithdraw { - assets: All.into(), - reserve, - xcm: Xcm(vec![ - Self::buy_execution(fee, &reserve, dest_weight_limit)?, - Self::deposit_asset(recipient, assets.len() as u32), - ]), - }, - ])) - } - - fn transfer_to_non_reserve_asset( - assets: MultiAssets, - fee: MultiAsset, - reserve: MultiLocation, - dest: MultiLocation, - recipient: MultiLocation, - dest_weight_limit: WeightLimit, - ) -> Result, DispatchError> { - let mut reanchored_dest = dest; - if reserve == MultiLocation::parent() { - if let MultiLocation { - parents: 1, - interior: X1(Parachain(id)), - } = dest - { - reanchored_dest = Parachain(id).into(); - } - } - - let max_assets = assets.len() as u32; - - Ok(Xcm(vec![ - WithdrawAsset(assets), - InitiateReserveWithdraw { - assets: All.into(), - reserve, - xcm: Xcm(vec![ - Self::buy_execution(Self::half(&fee), &reserve, dest_weight_limit.clone())?, - DepositReserveAsset { - assets: AllCounted(max_assets).into(), - dest: reanchored_dest, - xcm: Xcm(vec![ - Self::buy_execution(Self::half(&fee), &dest, dest_weight_limit)?, - Self::deposit_asset(recipient, max_assets), - ]), - }, - ]), - }, - ])) - } - - fn deposit_asset(recipient: MultiLocation, max_assets: u32) -> Instruction<()> { - DepositAsset { - assets: AllCounted(max_assets).into(), - beneficiary: recipient, - } - } - - fn buy_execution( - asset: MultiAsset, - at: &MultiLocation, - weight_limit: WeightLimit, - ) -> Result, DispatchError> { - let ancestry = T::SelfLocation::get(); - - let fees = asset.reanchored(at, ancestry.interior).map_err(|_| Error::::CannotReanchor)?; - - Ok(BuyExecution { fees, weight_limit }) - } - - /// Returns amount if `asset` is fungible, or zero. - fn fungible_amount(asset: &MultiAsset) -> u128 { - if let Fungible(amount) = &asset.fun { - *amount - } else { - Zero::zero() - } - } - - fn half(asset: &MultiAsset) -> MultiAsset { - let half_amount = Self::fungible_amount(asset) - .checked_div(2) - .expect("div 2 can't overflow; qed"); - MultiAsset { - fun: Fungible(half_amount), - id: asset.id, - } - } - } - - #[cfg(test)] - mod test { - use frame_support::assert_ok; - use xcm_simulator::TestExt; - - use crate::Event as SygmaXcmBridgeEvent; - use crate::mock::{ - ALICE, BOB, ENDOWED_BALANCE, - ParaA, ParaAssets, ParaB, ParaBalances, TestNet, - }; - use crate::mock::para::{assert_events, Runtime, RuntimeEvent, UsdtAssetId, UsdtLocation}; - - use super::*; - - #[test] - fn test_transfer_self_reserve_asset_to_parachain() { - TestNet::reset(); - - // sending native asset from parachain A to parachain B - ParaA::execute_with(|| { - assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE); - - // transfer parachain A native asset from Alice to parachain B on Bob - assert_ok!(BridgeImpl::::transfer(ALICE.into(), - (Concrete(MultiLocation::new(0, Here)), Fungible(10_000_000_000_000u128)).into(), - MultiLocation::new( - 1, - X2( - Parachain(2u32.into()), - Junction::AccountId32 { - network: None, - id: BOB.into(), - }, - ), - ) - )); - assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10_000_000_000_000u128); - - assert_events(vec![RuntimeEvent::SygmaXcmBridge(SygmaXcmBridgeEvent::XCMTransferSend { - asset: (Concrete(MultiLocation::new(0, Here)), Fungible(10_000_000_000_000u128)).into(), - origin: Junction::AccountId32 { - network: None, - id: ALICE.into(), - }.into(), - dest: MultiLocation::new( - 1, - X2( - Parachain(2u32.into()), - Junction::AccountId32 { - network: None, - id: BOB.into(), - }, - ), - ), - })]); - }); - - ParaB::execute_with(|| { - assert_eq!(ParaAssets::balance(1u32.into(), &ALICE), ENDOWED_BALANCE); - assert_eq!(ParaAssets::balance(1u32.into(), &BOB), 9_000_000_000_000u128); - }); - } - - #[test] - fn test_transfer_to_reserve_to_parachain() { - TestNet::reset(); - - let para_a_location = MultiLocation { - parents: 1, - interior: X1(Parachain(1)), - }; - - // Prepare step - // sending parachainB native asset to parachainA - ParaB::execute_with(|| { - assert_ok!(BridgeImpl::::transfer( + let fee_per_asset = T::MinXcmFee::get() + .iter() + .position(|a| a.0 == asset.id) + .map(|idx| T::MinXcmFee::get()[idx].1) + .unwrap(); + + let fee_to_dest: MultiAsset = (asset.id, fee_per_asset).into(); + + let xcm = XcmObject:: { + asset: asset.clone(), + fee: fee_to_dest, + origin: origin_location, + dest: dest_location, + recipient, + weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), + _unused: PhantomData, + }; + + let mut msg = xcm.create_instructions()?; + xcm.execute_instructions(&mut msg)?; + + Pallet::::deposit_event(Event::XCMTransferSend { + asset: Box::new(asset), + origin: Box::new(origin_location), + dest: Box::new(dest), + }); + + Ok(()) + } + } + + impl Pallet { + /// extract the dest_location, recipient_location + pub fn extract_dest(dest: &MultiLocation) -> Option<(MultiLocation, MultiLocation)> { + match (dest.parents, dest.first_interior()) { + (1, Some(Parachain(id))) => Some(( + MultiLocation::new(1, X1(Parachain(*id))), + MultiLocation::new(0, dest.interior().split_first().0), + )), + // parent: relay chain + (1, _) => Some((MultiLocation::parent(), MultiLocation::new(0, *dest.interior()))), + // local and children parachain have been filtered out in the TransactAsset + _ => None, + } + } + fn transfer_self_reserve_asset( + assets: MultiAssets, + fee: MultiAsset, + dest: MultiLocation, + + recipient: MultiLocation, + dest_weight_limit: WeightLimit, + ) -> Result, DispatchError> { + Ok(Xcm(vec![TransferReserveAsset { + assets: assets.clone(), + dest, + xcm: Xcm(vec![ + Self::buy_execution(fee, &dest, dest_weight_limit)?, + Self::deposit_asset(recipient, assets.len() as u32), + ]), + }])) + } + + fn transfer_to_reserve_asset( + assets: MultiAssets, + fee: MultiAsset, + reserve: MultiLocation, + recipient: MultiLocation, + dest_weight_limit: WeightLimit, + ) -> Result, DispatchError> { + Ok(Xcm(vec![ + WithdrawAsset(assets.clone()), + InitiateReserveWithdraw { + assets: All.into(), + reserve, + xcm: Xcm(vec![ + Self::buy_execution(fee, &reserve, dest_weight_limit)?, + Self::deposit_asset(recipient, assets.len() as u32), + ]), + }, + ])) + } + + fn transfer_to_non_reserve_asset( + assets: MultiAssets, + fee: MultiAsset, + reserve: MultiLocation, + dest: MultiLocation, + recipient: MultiLocation, + dest_weight_limit: WeightLimit, + ) -> Result, DispatchError> { + let mut reanchored_dest = dest; + if reserve == MultiLocation::parent() { + if let MultiLocation { parents: 1, interior: X1(Parachain(id)) } = dest { + reanchored_dest = Parachain(id).into(); + } + } + + let max_assets = assets.len() as u32; + + Ok(Xcm(vec![ + WithdrawAsset(assets), // local + InitiateReserveWithdraw { + // local + forward + assets: All.into(), + reserve, + xcm: Xcm(vec![ + Self::buy_execution(Self::half(&fee), &reserve, dest_weight_limit.clone())?, + DepositReserveAsset { + // + assets: AllCounted(max_assets).into(), + dest: reanchored_dest, + xcm: Xcm(vec![ + Self::buy_execution(Self::half(&fee), &dest, dest_weight_limit)?, + Self::deposit_asset(recipient, max_assets), + ]), + }, + ]), + }, + ])) + } + + fn deposit_asset(recipient: MultiLocation, max_assets: u32) -> Instruction<()> { + DepositAsset { assets: AllCounted(max_assets).into(), beneficiary: recipient } + } + + fn buy_execution( + asset: MultiAsset, + at: &MultiLocation, + weight_limit: WeightLimit, + ) -> Result, DispatchError> { + let ancestry = T::SelfLocation::get(); + + let fees = asset + .reanchored(at, ancestry.interior) + .map_err(|_| Error::::CannotReanchor)?; + + Ok(BuyExecution { fees, weight_limit }) + } + + /// Returns amount if `asset` is fungible, or zero. + fn fungible_amount(asset: &MultiAsset) -> u128 { + if let Fungible(amount) = &asset.fun { + *amount + } else { + Zero::zero() + } + } + + fn half(asset: &MultiAsset) -> MultiAsset { + let half_amount = + Self::fungible_amount(asset).checked_div(2).expect("div 2 can't overflow; qed"); + MultiAsset { fun: Fungible(half_amount), id: asset.id } + } + } + + #[cfg(test)] + mod test { + use frame_support::assert_ok; + use sp_std::{boxed::Box, vec}; + use xcm_simulator::TestExt; + + use crate::mock::para::{assert_events, Runtime, RuntimeEvent, UsdtAssetId, UsdtLocation}; + use crate::mock::{ + ParaA, ParaAssets, ParaB, ParaBalances, TestNet, ALICE, BOB, ENDOWED_BALANCE, + }; + use crate::Event as SygmaXcmBridgeEvent; + + use super::*; + + #[test] + fn test_transfer_self_reserve_asset_to_parachain() { + TestNet::reset(); + + // sending native asset from parachain A to parachain B + ParaA::execute_with(|| { + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE); + + // transfer parachain A native asset from Alice to parachain B on Bob + assert_ok!(BridgeImpl::::transfer( + ALICE.into(), + (Concrete(MultiLocation::new(0, Here)), Fungible(10_000_000_000_000u128)) + .into(), + MultiLocation::new( + 1, + X2( + Parachain(2u32), + Junction::AccountId32 { network: None, id: BOB.into() }, + ), + ) + )); + assert_eq!( + ParaBalances::free_balance(&ALICE), + ENDOWED_BALANCE - 10_000_000_000_000u128 + ); + + assert_events(vec![RuntimeEvent::SygmaXcmBridge( + SygmaXcmBridgeEvent::XCMTransferSend { + asset: Box::new( + ( + Concrete(MultiLocation::new(0, Here)), + Fungible(10_000_000_000_000u128), + ) + .into(), + ), + origin: Box::new( + Junction::AccountId32 { network: None, id: ALICE.into() }.into(), + ), + dest: Box::new(MultiLocation::new( + 1, + X2( + Parachain(2u32), + Junction::AccountId32 { network: None, id: BOB.into() }, + ), + )), + }, + )]); + }); + + ParaB::execute_with(|| { + assert_eq!(ParaAssets::balance(1u32, &ALICE), ENDOWED_BALANCE); + assert_eq!(ParaAssets::balance(1u32, &BOB), 9_000_000_000_000u128); + }); + } + + #[test] + fn test_transfer_to_reserve_to_parachain() { + TestNet::reset(); + + let para_a_location = MultiLocation { parents: 1, interior: X1(Parachain(1)) }; + + // Prepare step + // sending parachainB native asset to parachainA + ParaB::execute_with(|| { + assert_ok!(BridgeImpl::::transfer( ALICE.into(), (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), MultiLocation::new( 1, X2( - Parachain(1u32.into()), - Junction::AccountId32 { - network: None, - id: BOB.into() - } + Parachain(1u32), + Junction::AccountId32 { network: None, id: BOB.into() } ) ) )); - assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10); - - assert_events(vec![RuntimeEvent::SygmaXcmBridge(SygmaXcmBridgeEvent::XCMTransferSend { - asset: (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), - origin: Junction::AccountId32 { - network: None, - id: ALICE.into(), - }.into(), - dest: MultiLocation::new( - 1, - X2( - Parachain(1u32.into()), - Junction::AccountId32 { - network: None, - id: BOB.into(), - }, - ), - ), - })]); - }); - // Bob on parachainA should have parachainB's native asset - ParaA::execute_with(|| { - assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 10); - }); - - // sending parachainB's native asset from parachainA back to parachainB - ParaA::execute_with(|| { - assert_ok!(BridgeImpl::::transfer( + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10); + + assert_events(vec![RuntimeEvent::SygmaXcmBridge( + SygmaXcmBridgeEvent::XCMTransferSend { + asset: Box::new( + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), + ), + origin: Box::new( + Junction::AccountId32 { network: None, id: ALICE.into() }.into(), + ), + dest: Box::new(MultiLocation::new( + 1, + X2( + Parachain(1u32), + Junction::AccountId32 { network: None, id: BOB.into() }, + ), + )), + }, + )]); + }); + // Bob on parachainA should have parachainB's native asset + ParaA::execute_with(|| { + assert_eq!(ParaAssets::balance(0u32, &BOB), 10); + }); + + // sending parachainB's native asset from parachainA back to parachainB + ParaA::execute_with(|| { + assert_ok!(BridgeImpl::::transfer( BOB.into(), - (Concrete(para_a_location.clone()), Fungible(5u128)).into(), // sending 5 tokens + (Concrete(para_a_location), Fungible(5u128)).into(), // sending 5 tokens MultiLocation::new( 1, X2( - Parachain(2u32.into()), - Junction::AccountId32 { - network: None, - id: ALICE.into() - } + Parachain(2u32), + Junction::AccountId32 { network: None, id: ALICE.into() } ) ) )); - assert_eq!(ParaAssets::balance(0u32.into(), &BOB), 10 - 5); - - assert_events(vec![RuntimeEvent::SygmaXcmBridge(SygmaXcmBridgeEvent::XCMTransferSend { - asset: (Concrete(para_a_location.clone()), Fungible(5u128)).into(), - origin: Junction::AccountId32 { - network: None, - id: BOB.into(), - }.into(), - dest: MultiLocation::new( - 1, - X2( - Parachain(2u32.into()), - Junction::AccountId32 { - network: None, - id: ALICE.into(), - }, - ), - ), - })]); - }); - ParaA::execute_with(|| { - assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10 + 5); - }); - } - - #[test] - fn test_transfer_to_non_reserve_to_parachain() { - TestNet::reset(); - - // send USDT token from parachainA to parachainB - ParaA::execute_with(|| { - assert_ok!(BridgeImpl::::transfer(ALICE.into(), - (Concrete(UsdtLocation::get().into()), Fungible(10u128)).into(), - MultiLocation::new( - 1, - X2( - Parachain(2u32.into()), - Junction::AccountId32 { - network: None, - id: BOB.into(), - }, - ), - ) - )); - assert_eq!(ParaAssets::balance(UsdtAssetId::get().into(), &ALICE), ENDOWED_BALANCE - 10); - - assert_events(vec![RuntimeEvent::SygmaXcmBridge(SygmaXcmBridgeEvent::XCMTransferSend { - asset: (Concrete(UsdtLocation::get().into()), Fungible(10u128)).into(), - origin: Junction::AccountId32 { - network: None, - id: ALICE.into(), - }.into(), - dest: MultiLocation::new( - 1, - X2( - Parachain(2u32.into()), - Junction::AccountId32 { - network: None, - id: BOB.into(), - }, - ), - ), - })]); - }); - - ParaB::execute_with(|| { - assert_eq!(ParaAssets::balance(UsdtAssetId::get().into(), &BOB), 10); - }); - } - } + assert_eq!(ParaAssets::balance(0u32, &BOB), 10 - 5); + + assert_events(vec![RuntimeEvent::SygmaXcmBridge( + SygmaXcmBridgeEvent::XCMTransferSend { + asset: Box::new((Concrete(para_a_location), Fungible(5u128)).into()), + origin: Box::new( + Junction::AccountId32 { network: None, id: BOB.into() }.into(), + ), + dest: Box::new(MultiLocation::new( + 1, + X2( + Parachain(2u32), + Junction::AccountId32 { network: None, id: ALICE.into() }, + ), + )), + }, + )]); + }); + ParaA::execute_with(|| { + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10 + 5); + }); + } + + #[test] + fn test_transfer_to_non_reserve_to_parachain() { + TestNet::reset(); + + // send USDT token from parachainA to parachainB + ParaA::execute_with(|| { + assert_ok!(BridgeImpl::::transfer( + ALICE.into(), + (Concrete(UsdtLocation::get()), Fungible(10u128)).into(), + MultiLocation::new( + 1, + X2( + Parachain(2u32), + Junction::AccountId32 { network: None, id: BOB.into() }, + ), + ) + )); + assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE - 10); + + assert_events(vec![RuntimeEvent::SygmaXcmBridge( + SygmaXcmBridgeEvent::XCMTransferSend { + asset: Box::new((Concrete(UsdtLocation::get()), Fungible(10u128)).into()), + origin: Box::new( + Junction::AccountId32 { network: None, id: ALICE.into() }.into(), + ), + dest: Box::new(MultiLocation::new( + 1, + X2( + Parachain(2u32), + Junction::AccountId32 { network: None, id: BOB.into() }, + ), + )), + }, + )]); + }); + + ParaB::execute_with(|| { + assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &BOB), 10); + }); + } + } } - diff --git a/xcm-bridge/src/mock/mod.rs b/xcm-bridge/src/mock/mod.rs index 6b56ce22..c88fc221 100644 --- a/xcm-bridge/src/mock/mod.rs +++ b/xcm-bridge/src/mock/mod.rs @@ -3,14 +3,12 @@ #![cfg(test)] -use frame_support::sp_runtime::{ - AccountId32, - BuildStorage}; +use frame_support::sp_runtime::{AccountId32, BuildStorage}; use sp_io::TestExternalities; use xcm_simulator::{decl_test_network, decl_test_parachain, decl_test_relay_chain, TestExt}; -pub mod relay; pub mod para; +pub mod relay; pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); @@ -60,57 +58,48 @@ decl_test_network! { } pub fn para_ext(para_id: u32) -> TestExternalities { - use para::{Runtime, System}; - - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); - - let parachain_info_config = pallet_parachain_info::GenesisConfig:: { - parachain_id: para_id.into(), - phantom: Default::default(), - }; - parachain_info_config.assimilate_storage(&mut t).unwrap(); - - // set Alice and Bob with ENDOWED_BALANCE amount of native asset on every parachain - pallet_balances::GenesisConfig:: { - balances: vec![ - (ALICE, ENDOWED_BALANCE), - (BOB, ENDOWED_BALANCE), - ], - } - .assimilate_storage(&mut t) - .unwrap(); - - // set Alice with ENDOWED_BALANCE amount of USDT asset on every parachain - pallet_assets::GenesisConfig:: { - assets: vec![(1, ALICE, false, 1)], - metadata: vec![(1, "USDT".into(), "USDT".into(), 6)], - accounts: vec![(1, ALICE, ENDOWED_BALANCE)], - } - .assimilate_storage(&mut t) - .unwrap(); - - let mut ext = TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext + use para::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + let parachain_info_config = pallet_parachain_info::GenesisConfig:: { + parachain_id: para_id.into(), + phantom: Default::default(), + }; + parachain_info_config.assimilate_storage(&mut t).unwrap(); + + // set Alice and Bob with ENDOWED_BALANCE amount of native asset on every parachain + pallet_balances::GenesisConfig:: { + balances: vec![(ALICE, ENDOWED_BALANCE), (BOB, ENDOWED_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + // set Alice with ENDOWED_BALANCE amount of USDT asset on every parachain + pallet_assets::GenesisConfig:: { + assets: vec![(1, ALICE, false, 1)], + metadata: vec![(1, "USDT".into(), "USDT".into(), 6)], + accounts: vec![(1, ALICE, ENDOWED_BALANCE)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext } pub fn relay_ext() -> sp_io::TestExternalities { - use relay::{Runtime, System}; - - let mut t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); - - // set Alice with ENDOWED_BALANCE amount of native asset on relay chain - pallet_balances::GenesisConfig:: { - balances: vec![(ALICE, ENDOWED_BALANCE)], - } - .assimilate_storage(&mut t) - .unwrap(); - - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext + use relay::{Runtime, System}; + + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + // set Alice with ENDOWED_BALANCE amount of native asset on relay chain + pallet_balances::GenesisConfig:: { balances: vec![(ALICE, ENDOWED_BALANCE)] } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext } diff --git a/xcm-bridge/src/mock/para.rs b/xcm-bridge/src/mock/para.rs index 92d6bccc..494ec9d0 100644 --- a/xcm-bridge/src/mock/para.rs +++ b/xcm-bridge/src/mock/para.rs @@ -5,23 +5,35 @@ use std::marker::PhantomData; use std::result; use cumulus_primitives_core::{ChannelStatus, GetChannelInfo, ParaId, Weight}; +use frame_support::traits::{ConstU16, ConstU64, Nothing}; use frame_support::{ - construct_runtime, parameter_types, - traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything}, + construct_runtime, parameter_types, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything}, }; -use frame_support::traits::{ConstU16, ConstU64, Nothing}; use frame_system as system; use frame_system::EnsureRoot; use polkadot_parachain_primitives::primitives::Sibling; use sp_core::{crypto::AccountId32, H256}; use sp_runtime::traits::{IdentityLookup, Zero}; -use xcm::latest::{AssetId as XcmAssetId, InteriorMultiLocation, Junction, MultiAsset, MultiLocation, NetworkId, Weight as XCMWeight, XcmContext}; -use xcm::prelude::{Concrete, Fungible, GeneralKey, GlobalConsensus, Parachain, X1, X2, X3, XcmError}; -use xcm_builder::{AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit}; -use xcm_executor::{Assets as XcmAssets, Config, traits::{Error as ExecutionError, MatchesFungibles, WeightTrader, WithOriginFilter}, XcmExecutor}; +use xcm::latest::{ + AssetId as XcmAssetId, InteriorMultiLocation, Junction, MultiAsset, MultiLocation, NetworkId, + Weight as XCMWeight, XcmContext, +}; +use xcm::prelude::{ + Concrete, Fungible, GeneralKey, GlobalConsensus, Parachain, XcmError, X1, X2, X3, +}; +use xcm_builder::{ + AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, + FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SovereignSignedViaLocation, TakeWeightCredit, +}; +use xcm_executor::{ + traits::{Error as ExecutionError, MatchesFungibles, WeightTrader, WithOriginFilter}, + Assets as XcmAssets, Config, XcmExecutor, +}; use sygma_bridge_forwarder; -use sygma_bridge_forwarder::xcm_asset_transactor::XCMAssetTransactor; use crate as sygma_xcm_bridge; use crate::BridgeImpl; @@ -34,18 +46,17 @@ construct_runtime!( Balances: pallet_balances::{Pallet, Call, Config, Storage, Event}, Assets: pallet_assets::{Pallet, Call, Storage, Event}, - ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, + ParachainInfo: pallet_parachain_info::{Pallet, Storage, Config}, XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event}, CumulusXcm: cumulus_pallet_xcm::{Pallet, Event, Origin}, DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event}, - SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Event}, + SygmaXcmBridge: sygma_xcm_bridge::{Pallet, Event}, SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Event}, } ); - type Block = frame_system::mocking::MockBlock; pub(crate) type Balance = u128; @@ -55,154 +66,154 @@ pub type AccountId = AccountId32; pub type AssetId = u32; impl frame_system::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type BlockWeights = (); - type BlockLength = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = Everything; - type SystemWeightInfo = (); - type SS58Prefix = ConstU16<20>; - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = ConstU16<20>; + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; } parameter_types! { pub const ExistentialDeposit: Balance = 1; // 1 Unit deposit to create asset - pub const ApprovalDeposit: Balance = 1; + pub const ApprovalDeposit: Balance = 1; pub const AssetsStringLimit: u32 = 50; pub const MetadataDepositBase: Balance = 1; pub const MetadataDepositPerByte: Balance = 1; } impl pallet_balances::Config for Runtime { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<1>; - type MaxFreezes = ConstU32<1>; - type RuntimeHoldReason = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxHolds = ConstU32<1>; + type MaxFreezes = ConstU32<1>; + type RuntimeHoldReason = (); } impl pallet_assets::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Balance = Balance; - type AssetId = u32; - type AssetIdParameter = u32; - type Currency = Balances; - type CreateOrigin = AsEnsureOriginWithArg>; - type ForceOrigin = EnsureRoot; - type AssetDeposit = ExistentialDeposit; - type AssetAccountDeposit = ConstU128<10>; - type MetadataDepositBase = MetadataDepositBase; - type MetadataDepositPerByte = MetadataDepositPerByte; - type ApprovalDeposit = ApprovalDeposit; - type StringLimit = AssetsStringLimit; - type Freezer = (); - type Extra = (); - type CallbackHandle = (); - type WeightInfo = (); - type RemoveItemsLimit = ConstU32<5>; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = (); + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = EnsureRoot; + type AssetDeposit = ExistentialDeposit; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = MetadataDepositBase; + type MetadataDepositPerByte = MetadataDepositPerByte; + type ApprovalDeposit = ApprovalDeposit; + type StringLimit = AssetsStringLimit; + type Freezer = (); + type Extra = (); + type CallbackHandle = (); + type WeightInfo = (); + type RemoveItemsLimit = ConstU32<5>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } impl sygma_xcm_bridge::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Weigher = FixedWeightBounds; - type XcmExecutor = XcmExecutor; - type UniversalLocation = UniversalLocation; - type SelfLocation = SelfLocation; - type MinXcmFee = MinXcmFee; + type RuntimeEvent = RuntimeEvent; + type Weigher = FixedWeightBounds; + type XcmExecutor = XcmExecutor; + type UniversalLocation = UniversalLocation; + type SelfLocation = SelfLocation; + type MinXcmFee = MinXcmFee; } impl sygma_bridge_forwarder::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SygmaBridge = BridgeImpl; - type XCMBridge = BridgeImpl; + type RuntimeEvent = RuntimeEvent; + type SygmaBridge = BridgeImpl; + type XCMBridge = BridgeImpl; } impl pallet_parachain_info::Config for Runtime {} pub struct XcmConfig; impl Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - type AssetTransactor = XCMAssetTransactor, SygmaBridgeForwarder, >; - type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = NativeAsset; - type IsTeleporter = (); - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = AllTokensAreCreatedEqualToWeight; - type ResponseHandler = (); - type AssetTrap = (); - type AssetClaims = (); - type SubscriptionService = (); - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = ConstU32<64>; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = Everything; - type Aliasers = (); + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = (CurrencyTransactor, FungiblesTransactor); + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = NativeAsset; + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = AllTokensAreCreatedEqualToWeight; + type ResponseHandler = (); + type AssetTrap = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = ConstU32<64>; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = WithOriginFilter; + type SafeCallFilter = Everything; + type Aliasers = (); } pub type XcmRouter = ParachainXcmRouter; pub type Barrier = ( - TakeWeightCredit, - AllowTopLevelPaidExecutionFrom, - AllowUnpaidExecutionFrom, + TakeWeightCredit, + AllowTopLevelPaidExecutionFrom, + AllowUnpaidExecutionFrom, ); pub type LocationToAccountId = ( - ParentIsPreset, - SiblingParachainConvertsVia, - AccountId32Aliases, + ParentIsPreset, + SiblingParachainConvertsVia, + AccountId32Aliases, ); pub type XcmOriginToTransactDispatchOrigin = ( - SovereignSignedViaLocation, - RelayChainAsNative, - SiblingParachainAsNative, - SignedAccountId32AsNative, + SovereignSignedViaLocation, + RelayChainAsNative, + SiblingParachainAsNative, + SignedAccountId32AsNative, ); parameter_types! { - pub const RelayNetwork: NetworkId = NetworkId::Rococo; - pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub const RelayNetwork: NetworkId = NetworkId::Rococo; + pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); pub UnitWeightCost: XCMWeight = 1u64.into(); pub const MaxInstructions: u32 = 100; } parameter_types! { - pub NativeLocation: MultiLocation = MultiLocation::here(); - pub UsdtAssetId: AssetId = 1; + pub NativeLocation: MultiLocation = MultiLocation::here(); + pub UsdtAssetId: AssetId = 1; pub UsdtLocation: MultiLocation = MultiLocation::new( 1, X3( @@ -211,158 +222,150 @@ parameter_types! { slice_to_generalkey(b"usdt"), ), ); - pub CheckingAccount: AccountId32 = AccountId32::new([102u8; 32]); + pub CheckingAccount: AccountId32 = AccountId32::new([102u8; 32]); } parameter_types! { - pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))); + pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))); pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); - pub MinXcmFee: Vec<(XcmAssetId, u128)> = vec![(NativeLocation::get().into(), 1_000_000_000_000u128), (UsdtLocation::get().into(), 1_000_000u128)]; + pub MinXcmFee: Vec<(XcmAssetId, u128)> = vec![(NativeLocation::get().into(), 1_000_000_000_000u128), (UsdtLocation::get().into(), 1_000_000u128)]; } pub struct SimpleForeignAssetConverter(PhantomData<()>); - impl MatchesFungibles for SimpleForeignAssetConverter { - fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), ExecutionError> { - match (&a.fun, &a.id) { - (Fungible(ref amount), Concrete(ref id)) => { - if id == &UsdtLocation::get() { - Ok((UsdtAssetId::get(), *amount)) - } else { - Err(ExecutionError::AssetNotHandled) - } - } - _ => Err(ExecutionError::AssetNotHandled), - } - } + fn matches_fungibles(a: &MultiAsset) -> result::Result<(AssetId, Balance), ExecutionError> { + match (&a.fun, &a.id) { + (Fungible(ref amount), Concrete(ref id)) => { + if id == &UsdtLocation::get() { + Ok((UsdtAssetId::get(), *amount)) + } else { + Err(ExecutionError::AssetNotHandled) + } + }, + _ => Err(ExecutionError::AssetNotHandled), + } + } } pub type CurrencyTransactor = CurrencyAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // Convert an XCM MultiLocation into a local account id: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId32, - // We don't track any teleports of `Balances`. - (), + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId32, + // We don't track any teleports of `Balances`. + (), >; /// Means for transacting assets besides the native currency on this chain. pub type FungiblesTransactor = FungiblesAdapter< - // Use this fungibles implementation: - Assets, - // Use this currency when it is a fungible asset matching the given location or name: - SimpleForeignAssetConverter, - // Convert an XCM MultiLocation into a local account id: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId32, - // Disable teleport. - NoChecking, - // The account to use for tracking teleports. - CheckingAccount, + // Use this fungibles implementation: + Assets, + // Use this currency when it is a fungible asset matching the given location or name: + SimpleForeignAssetConverter, + // Convert an XCM MultiLocation into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId32, + // Disable teleport. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, >; pub struct ChannelInfo; impl GetChannelInfo for ChannelInfo { - fn get_channel_status(_id: ParaId) -> ChannelStatus { - ChannelStatus::Ready(10, 10) - } - fn get_channel_max(_id: ParaId) -> Option { - Some(usize::max_value()) - } + fn get_channel_status(_id: ParaId) -> ChannelStatus { + ChannelStatus::Ready(10, 10) + } + fn get_channel_max(_id: ParaId) -> Option { + Some(usize::max_value()) + } } impl cumulus_pallet_xcmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ChannelInfo = ChannelInfo; - type VersionWrapper = (); - type ExecuteOverweightOrigin = EnsureRoot; - type ControllerOrigin = EnsureRoot; - type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; - type PriceForSiblingDelivery = (); - type WeightInfo = (); + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; + type ChannelInfo = ChannelInfo; + type VersionWrapper = (); + type ExecuteOverweightOrigin = EnsureRoot; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type PriceForSiblingDelivery = (); + type WeightInfo = (); } impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; } impl cumulus_pallet_dmp_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = XcmExecutor; - type ExecuteOverweightOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; + type ExecuteOverweightOrigin = EnsureRoot; } pub struct AllTokensAreCreatedEqualToWeight(MultiLocation); impl WeightTrader for AllTokensAreCreatedEqualToWeight { - fn new() -> Self { - Self(MultiLocation::parent()) - } - - fn buy_weight(&mut self, weight: Weight, payment: XcmAssets, _context: &XcmContext) -> Result { - let asset_id = payment - .fungible - .iter() - .next() - .expect("Payment must be something; qed") - .0; - let required = MultiAsset { - id: asset_id.clone(), - fun: Fungible(weight.ref_time() as u128), - }; - - if let MultiAsset { - fun: _, - id: Concrete(ref id), - } = &required - { - self.0 = id.clone(); - } - - let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?; - Ok(unused) - } - - fn refund_weight(&mut self, weight: Weight, _context: &XcmContext) -> Option { - if weight.is_zero() { - None - } else { - Some((self.0.clone(), weight.ref_time() as u128).into()) - } - } + fn new() -> Self { + Self(MultiLocation::parent()) + } + + fn buy_weight( + &mut self, + weight: Weight, + payment: XcmAssets, + _context: &XcmContext, + ) -> Result { + let asset_id = payment.fungible.iter().next().expect("Payment must be something; qed").0; + let required = MultiAsset { id: *asset_id, fun: Fungible(weight.ref_time() as u128) }; + + if let MultiAsset { fun: _, id: Concrete(ref id) } = &required { + self.0 = *id; + } + + let unused = payment.checked_sub(required).map_err(|_| XcmError::TooExpensive)?; + Ok(unused) + } + + fn refund_weight(&mut self, weight: Weight, _context: &XcmContext) -> Option { + if weight.is_zero() { + None + } else { + Some((self.0, weight.ref_time() as u128).into()) + } + } } // Checks events against the latest. A contiguous set of events must be provided. They must // include the most recent event, but do not have to include every past event. pub fn assert_events(mut expected: Vec) { - let mut actual: Vec = - system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); + let mut actual: Vec = + system::Pallet::::events().iter().map(|e| e.event.clone()).collect(); - expected.reverse(); + expected.reverse(); - for evt in expected { - let next = actual.pop().expect("event expected"); - assert_eq!(next, evt, "Events don't match"); - } + for evt in expected { + let next = actual.pop().expect("event expected"); + assert_eq!(next, evt, "Events don't match"); + } } pub fn slice_to_generalkey(key: &[u8]) -> Junction { - let len = key.len(); - assert!(len <= 32); - GeneralKey { - length: len as u8, - data: { - let mut data = [0u8; 32]; - data[..len].copy_from_slice(key); - data - }, - } -} \ No newline at end of file + let len = key.len(); + assert!(len <= 32); + GeneralKey { + length: len as u8, + data: { + let mut data = [0u8; 32]; + data[..len].copy_from_slice(key); + data + }, + } +} diff --git a/xcm-bridge/src/mock/relay.rs b/xcm-bridge/src/mock/relay.rs index 81bcea87..745dc5c1 100644 --- a/xcm-bridge/src/mock/relay.rs +++ b/xcm-bridge/src/mock/relay.rs @@ -1,29 +1,29 @@ // The Licensed Work is (c) 2022 Sygma // SPDX-License-Identifier: LGPL-3.0-only -use cumulus_primitives_core::ParaId; +use cumulus_primitives_core::ParaId; +use frame_support::traits::{ConstU32, Nothing}; use frame_support::{ - construct_runtime, parameter_types, - traits::{Everything, ProcessMessage, ProcessMessageError}, - weights::{IdentityFee, Weight, WeightMeter}, + construct_runtime, parameter_types, + traits::{Everything, ProcessMessage, ProcessMessageError}, + weights::{IdentityFee, Weight, WeightMeter}, }; -use frame_support::traits::{ConstU32, Nothing}; use frame_system::EnsureRoot; use polkadot_runtime_parachains::{ - configuration, - inclusion::{AggregateMessageOrigin, UmpQueueId}, - origin, shared, + configuration, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, shared, }; use sp_core::H256; -use sp_runtime::{AccountId32, traits::IdentityLookup}; +use sp_runtime::{traits::IdentityLookup, AccountId32}; use xcm::latest::prelude::*; use xcm_builder::{ - AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, - ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, - IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, - TakeWeightCredit, UsingComponents, + AccountId32Aliases, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, + ChildParachainConvertsVia, CurrencyAdapter as XcmCurrencyAdapter, FixedWeightBounds, + IsConcrete, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, + TakeWeightCredit, UsingComponents, }; -use xcm_executor::{Config, traits::WithOriginFilter, XcmExecutor}; +use xcm_executor::{traits::WithOriginFilter, Config, XcmExecutor}; construct_runtime!( pub struct Runtime { @@ -45,29 +45,29 @@ parameter_types! { } impl frame_system::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = BlockHashCount; - type BlockWeights = (); - type BlockLength = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = Everything; - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<2>; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = Everything; + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<2>; } parameter_types! { @@ -77,46 +77,43 @@ parameter_types! { } impl pallet_balances::Config for Runtime { - type Balance = Balance; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ExistentialDeposit; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type FreezeIdentifier = (); - type MaxHolds = ConstU32<1>; - type MaxFreezes = ConstU32<1>; - type RuntimeHoldReason = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = (); + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxHolds = ConstU32<1>; + type MaxFreezes = ConstU32<1>; + type RuntimeHoldReason = (); } impl shared::Config for Runtime {} impl configuration::Config for Runtime { - type WeightInfo = configuration::TestWeightInfo; + type WeightInfo = configuration::TestWeightInfo; } parameter_types! { pub RooLocation: MultiLocation = Here.into(); pub const RococoNetwork: NetworkId = NetworkId::Rococo; - pub UniversalLocation: InteriorMultiLocation = Here; + pub UniversalLocation: InteriorMultiLocation = X1(GlobalConsensus(RococoNetwork::get())); } -pub type SovereignAccountOf = ( - ChildParachainConvertsVia, - AccountId32Aliases, -); +pub type SovereignAccountOf = + (ChildParachainConvertsVia, AccountId32Aliases); pub type LocalAssetTransactor = -XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; - + XcmCurrencyAdapter, SovereignAccountOf, AccountId, ()>; type LocalOriginConverter = ( - SovereignSignedViaLocation, - ChildParachainAsNative, - SignedAccountId32AsNative, + SovereignSignedViaLocation, + ChildParachainAsNative, + SignedAccountId32AsNative, ); pub type XcmRouter = super::RelayChainXcmRouter; @@ -137,61 +134,61 @@ parameter_types! { pub struct XcmConfig; impl Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - type AssetTransactor = LocalAssetTransactor; - type OriginConverter = LocalOriginConverter; - type IsReserve = (); - type IsTeleporter = (); - type UniversalLocation = UniversalLocation; - type Barrier = Barrier; - type Weigher = FixedWeightBounds; - type Trader = UsingComponents, RooLocation, AccountId, Balances, ()>; - type ResponseHandler = (); - type AssetTrap = (); - type AssetClaims = (); - type SubscriptionService = (); - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = WithOriginFilter; - type SafeCallFilter = Everything; - type Aliasers = (); + type RuntimeCall = RuntimeCall; + type XcmSender = XcmRouter; + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = FixedWeightBounds; + type Trader = UsingComponents, RooLocation, AccountId, Balances, ()>; + type ResponseHandler = (); + type AssetTrap = (); + type AssetClaims = (); + type SubscriptionService = (); + type PalletInstancesInfo = AllPalletsWithSystem; + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = (); + type UniversalAliases = Nothing; + type CallDispatcher = WithOriginFilter; + type SafeCallFilter = Everything; + type Aliasers = (); } pub type LocalOriginToLocation = SignedToAccountId32; impl pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; - type XcmRouter = XcmRouter; - // Anyone can execute XCM messages locally... - type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; - type XcmExecuteFilter = Everything; - type XcmExecutor = XcmExecutor; - type XcmTeleportFilter = Everything; - type XcmReserveTransferFilter = Everything; - type Weigher = FixedWeightBounds; - type UniversalLocation = UniversalLocation; - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; - type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; - type Currency = Balances; - type CurrencyMatcher = (); - type TrustedLockers = (); - type SovereignAccountOf = (); - type MaxLockers = ConstU32<8>; - type MaxRemoteLockConsumers = ConstU32<0>; - type RemoteLockConsumerIdentifier = (); - type WeightInfo = pallet_xcm::TestWeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type ReachableDest = ReachableDest; - type AdminOrigin = EnsureRoot; + type RuntimeEvent = RuntimeEvent; + type SendXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmRouter = XcmRouter; + // Anyone can execute XCM messages locally... + type ExecuteXcmOrigin = xcm_builder::EnsureXcmOrigin; + type XcmExecuteFilter = Everything; + type XcmExecutor = XcmExecutor; + type XcmTeleportFilter = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = FixedWeightBounds; + type UniversalLocation = UniversalLocation; + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100; + type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion; + type Currency = Balances; + type CurrencyMatcher = (); + type TrustedLockers = (); + type SovereignAccountOf = (); + type MaxLockers = ConstU32<8>; + type MaxRemoteLockConsumers = ConstU32<0>; + type RemoteLockConsumerIdentifier = (); + type WeightInfo = pallet_xcm::TestWeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type AdminOrigin = EnsureRoot; } impl origin::Config for Runtime {} @@ -205,37 +202,34 @@ parameter_types! { pub struct MessageProcessor; impl ProcessMessage for MessageProcessor { - type Origin = AggregateMessageOrigin; - - fn process_message( - message: &[u8], - origin: Self::Origin, - meter: &mut WeightMeter, - id: &mut [u8; 32], - ) -> Result { - let para = match origin { - AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, - }; - xcm_builder::ProcessXcmMessage::, RuntimeCall>::process_message( + type Origin = AggregateMessageOrigin; + + fn process_message( + message: &[u8], + origin: Self::Origin, + meter: &mut WeightMeter, + id: &mut [u8; 32], + ) -> Result { + let para = match origin { + AggregateMessageOrigin::Ump(UmpQueueId::Para(para)) => para, + }; + xcm_builder::ProcessXcmMessage::, RuntimeCall>::process_message( message, Junction::Parachain(para.into()), meter, id, ) - } + } } impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type Size = u32; - type HeapSize = MessageQueueHeapSize; - type MaxStale = MessageQueueMaxStale; - type ServiceWeight = MessageQueueServiceWeight; - type MessageProcessor = MessageProcessor; - type QueueChangeHandler = (); - type WeightInfo = (); - type QueuePausedQuery = (); + type RuntimeEvent = RuntimeEvent; + type Size = u32; + type HeapSize = MessageQueueHeapSize; + type MaxStale = MessageQueueMaxStale; + type ServiceWeight = MessageQueueServiceWeight; + type MessageProcessor = MessageProcessor; + type QueueChangeHandler = (); + type WeightInfo = (); + type QueuePausedQuery = (); } - - - From ac9ec82635ab89db24b02dcb4a85703a7383abf5 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Tue, 23 Jan 2024 10:59:07 -0500 Subject: [PATCH 26/30] finish the unit test for bridge forwarder --- bridge-forwarder/src/lib.rs | 243 ++++++++++++++++++- bridge-forwarder/src/xcm_asset_transactor.rs | 5 +- deny.toml | 2 +- 3 files changed, 242 insertions(+), 8 deletions(-) diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index 69f4a3be..986fa9f8 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -99,9 +99,15 @@ pub mod pallet { #[cfg(test)] mod test { - use frame_support::assert_ok; + use codec::Encode; + use frame_support::{ + assert_noop, assert_ok, traits::tokens::fungibles::Create as FungibleCerate, + }; + use hex_literal::hex; use xcm::latest::{Junction, XcmContext}; - use xcm::prelude::{AccountId32, Concrete, Fungible, Here, Parachain, X1, X2}; + use xcm::prelude::{ + AccountId32, Concrete, Fungible, GeneralKey, Here, Parachain, XcmError, X1, X2, X5, + }; use xcm::v3::Junction::GeneralIndex; use xcm::v3::{MultiAsset, MultiLocation}; use xcm_executor::traits::TransactAsset; @@ -109,9 +115,10 @@ pub mod pallet { use sygma_traits::{AssetTypeIdentifier, TransactorForwarder}; use crate::mock::{ - assert_events, new_test_ext, Assets, Balances, CurrencyTransactor, - ForwarderImplRuntime, FungiblesTransactor, ParachainInfo, RuntimeEvent, - SygmaBridgeForwarder, UsdtAssetId, UsdtLocation, ALICE, BOB, + assert_events, new_test_ext, slice_to_generalkey, Assets, Balances, CurrencyTransactor, + ForwarderImplRuntime, FungiblesTransactor, ParachainInfo, Runtime, RuntimeEvent, + RuntimeOrigin, SygmaBridgeForwarder, UsdtAssetId, UsdtLocation, ALICE, ASSET_OWNER, + BOB, ENDOWED_BALANCE, }; use crate::{ xcm_asset_transactor::XCMAssetTransactor, Event as SygmaBridgeForwarderEvent, @@ -211,6 +218,11 @@ pub mod pallet { )); assert_eq!(Balances::free_balance(BOB), 10u128); + // Register foreign asset (USDT) with asset id 1 + assert_ok!( as FungibleCerate< + ::AccountId, + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); + // send foreign asset to local parachain let local_foreign_asset: MultiAsset = (Concrete(UsdtLocation::get()), Fungible(10u128)).into(); @@ -227,5 +239,226 @@ pub mod pallet { assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), 10u128); }) } + + #[test] + fn test_xcm_asset_transactor_outer() { + new_test_ext().execute_with(|| { + let dest_domain_id = 1; + let outer_recipient: MultiLocation = MultiLocation::new( + 1, + X5( + Parachain(1000), + GeneralKey { + length: 5, + data: hex![ + "7379676d61000000000000000000000000000000000000000000000000000000" + ], + }, + GeneralKey { + length: 12, + data: hex![ + "7379676d612d6272696467650000000000000000000000000000000000000000" + ], + }, + GeneralIndex(dest_domain_id), + slice_to_generalkey(b"ethereum recipient"), + ), + ); + + // send native asset to the outer world + let native_asset: MultiAsset = + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + assert_ok!(XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::deposit_asset( + &native_asset, + &outer_recipient, + &XcmContext::with_message_id([0; 32]) + )); + // asset tmp holder for outer world transfer + let tmp_account = sp_io::hashing::blake2_256( + &MultiLocation::new(0, X1(GeneralKey { length: 8, data: [1u8; 32] })).encode(), + ); + assert_eq!( + Balances::free_balance(sp_runtime::AccountId32::from(tmp_account)), + 10u128 + ); + + // Register foreign asset (USDT) with asset id 1 + assert_ok!( as FungibleCerate< + ::AccountId, + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); + + // send foreign asset to the outer world + let foreign_asset: MultiAsset = + (Concrete(UsdtLocation::get()), Fungible(10u128)).into(); + assert_ok!(XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::deposit_asset( + &foreign_asset, + &outer_recipient, + &XcmContext::with_message_id([0; 32]) + )); + // asset tmp holder for outer world transfer + let tmp_account = sp_io::hashing::blake2_256( + &MultiLocation::new(0, X1(GeneralKey { length: 8, data: [1u8; 32] })).encode(), + ); + assert_eq!( + Assets::balance(UsdtAssetId::get(), sp_runtime::AccountId32::from(tmp_account)), + 10u128 + ); + }) + } + + #[test] + fn test_xcm_asset_transactor_substrate() { + new_test_ext().execute_with(|| { + let substrate_recipient: MultiLocation = MultiLocation::new( + 1, + X2(Parachain(2005), slice_to_generalkey(b"substrate recipient")), + ); + + // send native asset to the substrate world + let native_asset: MultiAsset = + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + assert_ok!(XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::deposit_asset( + &native_asset, + &substrate_recipient, + &XcmContext::with_message_id([0; 32]) + )); + // asset tmp holder for substrate world transfer + let tmp_account = sp_io::hashing::blake2_256( + &MultiLocation::new(0, X1(GeneralKey { length: 8, data: [2u8; 32] })).encode(), + ); + assert_eq!( + Balances::free_balance(sp_runtime::AccountId32::from(tmp_account)), + 10u128 + ); + + // Register foreign asset (USDT) with asset id 1 + assert_ok!( as FungibleCerate< + ::AccountId, + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); + + // send foreign asset to the outer world + let foreign_asset: MultiAsset = + (Concrete(UsdtLocation::get()), Fungible(10u128)).into(); + assert_ok!(XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::deposit_asset( + &foreign_asset, + &substrate_recipient, + &XcmContext::with_message_id([0; 32]) + )); + // asset tmp holder for substrate world transfer + let tmp_account = sp_io::hashing::blake2_256( + &MultiLocation::new(0, X1(GeneralKey { length: 8, data: [2u8; 32] })).encode(), + ); + assert_eq!( + Assets::balance(UsdtAssetId::get(), sp_runtime::AccountId32::from(tmp_account)), + 10u128 + ); + }) + } + + #[test] + fn test_xcm_asset_transactor_not_supported_dest() { + new_test_ext().execute_with(|| { + let none_supported_recipient: MultiLocation = MultiLocation::new( + 2, + X2(Parachain(2005), slice_to_generalkey(b"substrate recipient")), + ); + + // send native asset to non-supported world + let native_asset: MultiAsset = + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + assert_noop!( + XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::deposit_asset( + &native_asset, + &none_supported_recipient, + &XcmContext::with_message_id([0; 32]) + ), + XcmError::DestinationUnsupported + ); + + // asset tmp holder for substrate world and outer world transfer, should not receive any token + let tmp_account_outer = sp_io::hashing::blake2_256( + &MultiLocation::new(0, X1(GeneralKey { length: 8, data: [1u8; 32] })).encode(), + ); + assert_eq!( + Balances::free_balance(sp_runtime::AccountId32::from(tmp_account_outer)), + 0u128 + ); + let tmp_account_substrate = sp_io::hashing::blake2_256( + &MultiLocation::new(0, X1(GeneralKey { length: 8, data: [2u8; 32] })).encode(), + ); + assert_eq!( + Balances::free_balance(sp_runtime::AccountId32::from(tmp_account_substrate)), + 0u128 + ); + }) + } + + #[test] + fn test_xcm_asset_transactor_withdraw() { + new_test_ext().execute_with(|| { + let from_account: MultiLocation = + MultiLocation::new(0, X1(AccountId32 { network: None, id: ALICE.into() })); + + // withdraw native asset from Alice + let native_asset: MultiAsset = + (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); + assert_ok!(XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::withdraw_asset(&native_asset, &from_account, None)); + assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - 10u128); + + // Register foreign asset (USDT) with asset id 1 + assert_ok!( as FungibleCerate< + ::AccountId, + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); + // Mint some USDT to ALICE for test + assert_ok!(Assets::mint( + RuntimeOrigin::signed(ASSET_OWNER), + codec::Compact(1), + ALICE, + ENDOWED_BALANCE, + )); + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE); + + // withdraw foreign asset from Alice + let foreign_asset: MultiAsset = + (Concrete(UsdtLocation::get()), Fungible(10u128)).into(); + assert_ok!(XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::withdraw_asset(&foreign_asset, &from_account, None)); + assert_eq!(Assets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE - 10u128); + }) + } } } diff --git a/bridge-forwarder/src/xcm_asset_transactor.rs b/bridge-forwarder/src/xcm_asset_transactor.rs index fc3050fb..ae3e6c66 100644 --- a/bridge-forwarder/src/xcm_asset_transactor.rs +++ b/bridge-forwarder/src/xcm_asset_transactor.rs @@ -43,9 +43,10 @@ impl< match who.interior { // sygma: 7379676d61000000000000000000000000000000000000000000000000000000 // sygma-bridge: 7379676d612d6272696467650000000000000000000000000000000000000000 + // outer world multilocation pattern: { Parachain(1000), GeneralKey { length: 5, data: b"sygma"}, GeneralKey { length: 12, data: b"sygma-bridge"}, GeneralIndex(domainID), GeneralKey { length: length_of_recipient_address, data: recipient_address} } X5(Parachain(1000), GeneralKey { length: 5, data: hex!["7379676d61000000000000000000000000000000000000000000000000000000"]}, GeneralKey { length: 12, data: hex!["7379676d612d6272696467650000000000000000000000000000000000000000"]}, GeneralIndex(..), GeneralKey { .. }) => { - // check if the asset is native or foreign, and deposit the asset to a tmp account first - let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey { length: 8, data: [2u8; 32] })).encode()); + // check if the asset is native or foreign, and deposit the asset to a tmp account first + let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey { length: 8, data: [1u8; 32] })).encode()); if AssetTypeChecker::is_native_asset(what) { CurrencyTransactor::deposit_asset(&what.clone(), &Junction::AccountId32 { network: None, id: tmp_account }.into(), context)?; } else { diff --git a/deny.toml b/deny.toml index 2c8d75b0..36da1d8a 100644 --- a/deny.toml +++ b/deny.toml @@ -36,7 +36,7 @@ targets = [ # (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html) # these are the unlicensed dependencies exclude = ["xcm", "xcm-executor", "xcm-builder", "cumulus-primitives-core", "cumulus-primitives-utility", "parachains-common", - "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "ring"] + "polkadot-core-primitives", "polkadot-parachain-primitives", "polkadot-primitives", "ring", "cumulus-pallet-xcm"] # If true, metadata will be collected with `--all-features`. Note that this can't # be toggled off if true, if you want to conditionally enable `--all-features` it # is recommended to pass `--all-features` on the cmd line instead From ed06a6a546c8c9d4d46469d7b098541631558523 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Mon, 29 Jan 2024 13:46:12 -0500 Subject: [PATCH 27/30] fix the unit tests --- Cargo.lock | 32 +++- bridge-forwarder/src/lib.rs | 1 - xcm-bridge/Cargo.toml | 4 + xcm-bridge/src/lib.rs | 372 ++++++++++++++++++++++++++++-------- xcm-bridge/src/mock/mod.rs | 28 +-- xcm-bridge/src/mock/para.rs | 33 ++-- 6 files changed, 352 insertions(+), 118 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0eac108f..6c304b84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,9 +206,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" dependencies = [ "anstyle", "anstyle-parse", @@ -2279,6 +2279,16 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + [[package]] name = "env_logger" version = "0.10.0" @@ -2292,6 +2302,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "environmental" version = "1.1.4" @@ -2460,7 +2483,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger", + "env_logger 0.10.0", "log", ] @@ -9804,8 +9827,11 @@ dependencies = [ "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", "cumulus-primitives-utility", + "env_logger 0.11.1", "frame-support", "frame-system", + "half", + "log", "pallet-assets", "pallet-balances", "pallet-message-queue", diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index 986fa9f8..d4527075 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -80,7 +80,6 @@ pub mod pallet { } pub struct NativeAssetTypeIdentifier(PhantomData); - impl> AssetTypeIdentifier for NativeAssetTypeIdentifier { /// check if the given MultiAsset is a native asset fn is_native_asset(asset: &MultiAsset) -> bool { diff --git a/xcm-bridge/Cargo.toml b/xcm-bridge/Cargo.toml index f5fdf4b6..3752f290 100644 --- a/xcm-bridge/Cargo.toml +++ b/xcm-bridge/Cargo.toml @@ -31,6 +31,8 @@ cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.gi # Local sygma-traits = { path = "../traits", default-features = false } sygma-bridge-forwarder = { path = "../bridge-forwarder", default-features = false } +half = { version = "2.3.1", default-features = false } +log = "0.4.20" [dev-dependencies] # Substrate @@ -64,6 +66,8 @@ cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk sygma-traits = { path = "../traits" } pallet-parachain-info = { path = "../parachain-info" } +env_logger = "0.11.1" + [features] default = ["std"] std = [ diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 7ffa3296..e1ee9502 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -16,7 +16,7 @@ pub mod pallet { use xcm::latest::{prelude::*, MultiLocation, Weight as XCMWeight}; use xcm_executor::traits::WeightBounds; - use sygma_traits::{AssetReserveLocationParser, Bridge}; + use sygma_traits::{AssetReserveLocationParser, AssetTypeIdentifier, Bridge}; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -32,6 +32,8 @@ pub mod pallet { type XcmExecutor: ExecuteXcm; + type AssetReservedChecker: AssetTypeIdentifier; + type UniversalLocation: Get; #[pallet::constant] @@ -41,6 +43,7 @@ pub mod pallet { type MinXcmFee: Get>; } + #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, TypeInfo)] pub enum TransferKind { /// Transfer self reserve asset. assets reserved by the origin chain SelfReserveAsset, @@ -67,10 +70,11 @@ pub mod pallet { InvalidDestination, UnknownTransferType, CannotReanchor, - NoXcmMiNFeeSet, + NoXcmMinFeeSet, + AssetReservedLocationNotFound, } - #[derive(PartialEq, Eq, Clone, Encode, Decode)] + #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] struct XcmObject { asset: MultiAsset, fee: MultiAsset, @@ -82,7 +86,7 @@ pub mod pallet { } pub trait XcmHandler { - fn transfer_kind(&self) -> Option; + fn transfer_kind(&self, asset_reserved_location: MultiLocation) -> Option; fn create_instructions(&self) -> Result, DispatchError>; fn execute_instructions( &self, @@ -91,12 +95,10 @@ pub mod pallet { } impl XcmHandler for XcmObject { - fn transfer_kind(&self) -> Option { - let asset_location = Pallet::::reserved_location(&self.asset.clone())?; - if asset_location == T::SelfLocation::get() { + fn transfer_kind(&self, asset_reserved_location: MultiLocation) -> Option { + if T::AssetReservedChecker::is_native_asset(&self.asset.clone()) { Some(TransferKind::SelfReserveAsset) - } else if asset_location == self.dest { - // TODO: parse to dest multilocation, not asset local + } else if asset_reserved_location == self.dest { Some(TransferKind::ToReserve) } else { Some(TransferKind::ToNonReserve) @@ -104,7 +106,10 @@ pub mod pallet { } fn create_instructions(&self) -> Result, DispatchError> { - let kind = Self::transfer_kind(self).ok_or(Error::::UnknownTransferType)?; + let asset_reserved_location = Pallet::::reserved_location(&self.asset.clone()) + .ok_or(Error::::AssetReservedLocationNotFound)?; + let kind = Self::transfer_kind(self, asset_reserved_location) + .ok_or(Error::::UnknownTransferType)?; let mut assets = MultiAssets::new(); assets.push(self.asset.clone()); @@ -127,7 +132,7 @@ pub mod pallet { TransferKind::ToNonReserve => Pallet::::transfer_to_non_reserve_asset( assets, self.fee.clone(), - self.dest, + asset_reserved_location, self.dest, self.recipient, WeightLimit::Limited(self.weight), @@ -162,10 +167,25 @@ pub mod pallet { impl AssetReserveLocationParser for Pallet { fn reserved_location(asset: &MultiAsset) -> Option { - match (&asset.id, &asset.fun) { + let location = match (&asset.id, &asset.fun) { + // So far our native asset is concrete (Concrete(id), Fungible(_)) => Some(*id), _ => None, - } + }; + + location.and_then(|id| { + match (id.parents, id.first_interior()) { + // Sibling parachain + (1, Some(Parachain(id))) => Some(MultiLocation::new(1, X1(Parachain(*id)))), + // Parent + (1, _) => Some(MultiLocation::parent()), + // Children parachain + (0, Some(Parachain(id))) => Some(MultiLocation::new(0, X1(Parachain(*id)))), + // Local: (0, Here) + (0, None) => Some(id), + _ => None, + } + }) } } @@ -185,23 +205,22 @@ pub mod pallet { .position(|a| a.0 == asset.id) .map(|idx| { T::MinXcmFee::get()[idx].1 }) .is_some(), - Error::::NoXcmMiNFeeSet + Error::::NoXcmMinFeeSet ); let fee_per_asset = T::MinXcmFee::get() .iter() .position(|a| a.0 == asset.id) .map(|idx| T::MinXcmFee::get()[idx].1) .unwrap(); - - let fee_to_dest: MultiAsset = (asset.id, fee_per_asset).into(); + let min_fee_to_dest: MultiAsset = (asset.id, fee_per_asset).into(); let xcm = XcmObject:: { asset: asset.clone(), - fee: fee_to_dest, + fee: min_fee_to_dest, origin: origin_location, dest: dest_location, recipient, - weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), + weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), // TODO: configure weight _unused: PhantomData, }; @@ -236,7 +255,6 @@ pub mod pallet { assets: MultiAssets, fee: MultiAsset, dest: MultiLocation, - recipient: MultiLocation, dest_weight_limit: WeightLimit, ) -> Result, DispatchError> { @@ -288,15 +306,13 @@ pub mod pallet { let max_assets = assets.len() as u32; Ok(Xcm(vec![ - WithdrawAsset(assets), // local + WithdrawAsset(assets), InitiateReserveWithdraw { - // local + forward assets: All.into(), reserve, xcm: Xcm(vec![ Self::buy_execution(Self::half(&fee), &reserve, dest_weight_limit.clone())?, DepositReserveAsset { - // assets: AllCounted(max_assets).into(), dest: reanchored_dest, xcm: Xcm(vec![ @@ -345,22 +361,71 @@ pub mod pallet { #[cfg(test)] mod test { - use frame_support::assert_ok; + use frame_support::{ + assert_ok, traits::tokens::fungibles::metadata::Mutate as MetaMutate, + traits::tokens::fungibles::Create as FungibleCerate, + }; + use polkadot_parachain_primitives::primitives::Sibling; + use sp_runtime::traits::AccountIdConversion; + use sp_runtime::AccountId32; use sp_std::{boxed::Box, vec}; use xcm_simulator::TestExt; - use crate::mock::para::{assert_events, Runtime, RuntimeEvent, UsdtAssetId, UsdtLocation}; + use super::*; + use crate::mock::para::{ + assert_events, Assets, NativeAssetId, PBALocation, Runtime, RuntimeEvent, + RuntimeOrigin, UsdtAssetId, UsdtLocation, + }; use crate::mock::{ - ParaA, ParaAssets, ParaB, ParaBalances, TestNet, ALICE, BOB, ENDOWED_BALANCE, + ParaA, ParaAssets, ParaB, ParaBalances, ParaC, TestNet, ALICE, ASSET_OWNER, BOB, + ENDOWED_BALANCE, }; use crate::Event as SygmaXcmBridgeEvent; - use super::*; + fn init_logger() { + let _ = env_logger::builder() + // Include all events in tests + .filter_level(log::LevelFilter::max()) + // Ensure events are captured by `cargo test` + .is_test(true) + // Ignore errors initializing the logger if tests race to configure it + .try_init(); + } + + fn sibling_account(para_id: u32) -> AccountId32 { + Sibling::from(para_id).into_account_truncating() + } #[test] fn test_transfer_self_reserve_asset_to_parachain() { + init_logger(); + TestNet::reset(); + // sending 10 tokens + let amount = 10_000_000_000_000u128; + let fee = 4u128; + + ParaB::execute_with(|| { + // ParaB register the native asset of paraA + assert_ok!( as FungibleCerate< + ::AccountId, + >>::create(NativeAssetId::get(), ASSET_OWNER, true, 1,)); + + assert_ok!( as MetaMutate< + ::AccountId, + >>::set( + NativeAssetId::get(), + &ASSET_OWNER, + b"ParaAAsset".to_vec(), + b"PAA".to_vec(), + 12, + )); + + // make sure Bob on parachain B holds none of NativeAsset of paraA + assert_eq!(ParaAssets::balance(NativeAssetId::get(), &BOB), 0u128); + }); + // sending native asset from parachain A to parachain B ParaA::execute_with(|| { assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE); @@ -368,8 +433,7 @@ pub mod pallet { // transfer parachain A native asset from Alice to parachain B on Bob assert_ok!(BridgeImpl::::transfer( ALICE.into(), - (Concrete(MultiLocation::new(0, Here)), Fungible(10_000_000_000_000u128)) - .into(), + (Concrete(MultiLocation::new(0, Here)), Fungible(amount)).into(), MultiLocation::new( 1, X2( @@ -378,19 +442,14 @@ pub mod pallet { ), ) )); - assert_eq!( - ParaBalances::free_balance(&ALICE), - ENDOWED_BALANCE - 10_000_000_000_000u128 - ); + + // Alice should lost the amount of native asset of paraA + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - amount); assert_events(vec![RuntimeEvent::SygmaXcmBridge( SygmaXcmBridgeEvent::XCMTransferSend { asset: Box::new( - ( - Concrete(MultiLocation::new(0, Here)), - Fungible(10_000_000_000_000u128), - ) - .into(), + (Concrete(MultiLocation::new(0, Here)), Fungible(amount)).into(), ), origin: Box::new( Junction::AccountId32 { network: None, id: ALICE.into() }.into(), @@ -404,41 +463,88 @@ pub mod pallet { )), }, )]); + + // sibling_account of B on A should have amount of native asset as well + assert_eq!(ParaBalances::free_balance(sibling_account(2)), amount); }); ParaB::execute_with(|| { - assert_eq!(ParaAssets::balance(1u32, &ALICE), ENDOWED_BALANCE); - assert_eq!(ParaAssets::balance(1u32, &BOB), 9_000_000_000_000u128); + // Bob should get amount - fee of the native asset of paraA on paraB + assert_eq!(ParaAssets::balance(NativeAssetId::get(), &BOB), amount - fee); }); } #[test] fn test_transfer_to_reserve_to_parachain() { + init_logger(); + TestNet::reset(); - let para_a_location = MultiLocation { parents: 1, interior: X1(Parachain(1)) }; + // sending 10 tokens + let amount = 10_000_000_000_000u128; + let fee = 4u128; - // Prepare step - // sending parachainB native asset to parachainA + // register PBA on paraA + ParaA::execute_with(|| { + assert_ok!( as FungibleCerate< + ::AccountId, + >>::create(NativeAssetId::get(), ASSET_OWNER, true, 1,)); + + assert_ok!( as MetaMutate< + ::AccountId, + >>::set( + NativeAssetId::get(), + &ASSET_OWNER, + b"ParaBAsset".to_vec(), + b"PBA".to_vec(), + 12, + )); + }); + + // transfer PBA from Alice on parachain B to Alice on parachain A ParaB::execute_with(|| { + // Bob now has ENDOWED_BALANCE of PBB on parachain B + assert_eq!(ParaBalances::free_balance(&BOB), ENDOWED_BALANCE); + assert_ok!(BridgeImpl::::transfer( ALICE.into(), - (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), + (Concrete(MultiLocation::new(0, Here)), Fungible(amount)).into(), MultiLocation::new( 1, X2( Parachain(1u32), + Junction::AccountId32 { network: None, id: ALICE.into() }, + ), + ) + )); + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - amount); + assert_eq!(ParaBalances::free_balance(sibling_account(1)), amount); + }); + + // transfer PBA back to parachain B + ParaA::execute_with(|| { + assert_eq!(ParaAssets::balance(NativeAssetId::get(), &ALICE), amount - fee); + + // transfer PBA back to Bob on parachain B with (amount - fee) + assert_ok!(BridgeImpl::::transfer( + ALICE.into(), + (PBALocation::get(), Fungible(amount - fee)).into(), + MultiLocation::new( + 1, + X2( + Parachain(2u32), Junction::AccountId32 { network: None, id: BOB.into() } ) ) )); - assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10); + // now Alice holds 0 of PBA + assert_eq!(ParaAssets::balance(NativeAssetId::get(), &ALICE), 0u128); assert_events(vec![RuntimeEvent::SygmaXcmBridge( SygmaXcmBridgeEvent::XCMTransferSend { asset: Box::new( - (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(), + (Concrete(PBALocation::get()), Fungible(amount - fee)).into(), ), origin: Box::new( Junction::AccountId32 { network: None, id: ALICE.into() }.into(), @@ -446,64 +552,143 @@ pub mod pallet { dest: Box::new(MultiLocation::new( 1, X2( - Parachain(1u32), + Parachain(2u32), Junction::AccountId32 { network: None, id: BOB.into() }, ), )), }, )]); }); - // Bob on parachainA should have parachainB's native asset - ParaA::execute_with(|| { - assert_eq!(ParaAssets::balance(0u32, &BOB), 10); + + ParaB::execute_with(|| { + // Bob should get amount - fee * 2 bcs there are two times of xcm transfer + assert_eq!(ParaBalances::free_balance(&BOB), ENDOWED_BALANCE + amount - fee * 2); + assert_eq!(ParaBalances::free_balance(sibling_account(1)), 4u128); + }); + } + + #[test] + fn test_transfer_to_non_reserve_to_parachain() { + init_logger(); + + TestNet::reset(); + + // register token on Parachain C + ParaC::execute_with(|| { + assert_ok!( as FungibleCerate< + ::AccountId, + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); + assert_ok!( as MetaMutate< + ::AccountId, + >>::set( + UsdtAssetId::get(), + &ASSET_OWNER, + b"USDT".to_vec(), + b"USDT".to_vec(), + 12, + )); + + // mint USDT to ASSET_OWNER + assert_ok!(Assets::mint( + RuntimeOrigin::signed(ASSET_OWNER), + UsdtAssetId::get(), + ASSET_OWNER, + ENDOWED_BALANCE, + )); + + // checking USDT balances + assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &ASSET_OWNER), ENDOWED_BALANCE); + assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &ALICE), 0u128); + assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &BOB), 0u128); + + // checking native asset balances + assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE); + assert_eq!(ParaBalances::free_balance(&BOB), ENDOWED_BALANCE); + + // make sure the sibling_account of parachain A has enough native asset + // this is used in WithdrawAsset xcm instruction in InitiateReserveWithdraw + assert_ok!(ParaBalances::transfer_keep_alive( + RuntimeOrigin::signed(ASSET_OWNER), + Sibling::from(1u32).into_account_truncating(), + 1_000_000_000_000_000_u128 + )); + assert_eq!( + ParaBalances::free_balance(sibling_account(1)), + 1_000_000_000_000_000_u128 + ); + + // sibling_account of B has 0 balance at this moment + assert_eq!(ParaBalances::free_balance(sibling_account(2)), 0u128); }); - // sending parachainB's native asset from parachainA back to parachainB + // register token on Parachain A ParaA::execute_with(|| { + assert_ok!( as FungibleCerate< + ::AccountId, + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); + assert_ok!( as MetaMutate< + ::AccountId, + >>::set( + UsdtAssetId::get(), + &ASSET_OWNER, + b"USDT".to_vec(), + b"USDT".to_vec(), + 12, + )); + }); + + // transfer some USDT from C to Alice on A + ParaC::execute_with(|| { assert_ok!(BridgeImpl::::transfer( - BOB.into(), - (Concrete(para_a_location), Fungible(5u128)).into(), // sending 5 tokens + ASSET_OWNER.into(), + (Concrete(UsdtLocation::get()), Fungible(100_000_000u128)).into(), MultiLocation::new( 1, X2( - Parachain(2u32), - Junction::AccountId32 { network: None, id: ALICE.into() } - ) + Parachain(1u32), + Junction::AccountId32 { network: None, id: ALICE.into() }, + ), ) )); - - assert_eq!(ParaAssets::balance(0u32, &BOB), 10 - 5); - - assert_events(vec![RuntimeEvent::SygmaXcmBridge( - SygmaXcmBridgeEvent::XCMTransferSend { - asset: Box::new((Concrete(para_a_location), Fungible(5u128)).into()), - origin: Box::new( - Junction::AccountId32 { network: None, id: BOB.into() }.into(), - ), - dest: Box::new(MultiLocation::new( - 1, - X2( - Parachain(2u32), - Junction::AccountId32 { network: None, id: ALICE.into() }, - ), - )), - }, - )]); + assert_eq!( + ParaAssets::balance(UsdtAssetId::get(), &ASSET_OWNER), + ENDOWED_BALANCE - 100_000_000u128 + ); }); + + // Alice should get the USDT token - fee ParaA::execute_with(|| { - assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - 10 + 5); + assert_eq!( + ParaAssets::balance(UsdtAssetId::get(), &ALICE), + 100_000_000u128 - 4u128 + ); }); - } - #[test] - fn test_transfer_to_non_reserve_to_parachain() { - TestNet::reset(); + // Parachain B register USDT token + ParaB::execute_with(|| { + assert_ok!( as FungibleCerate< + ::AccountId, + >>::create(UsdtAssetId::get(), ASSET_OWNER, true, 1,)); + assert_ok!( as MetaMutate< + ::AccountId, + >>::set( + UsdtAssetId::get(), + &ASSET_OWNER, + b"USDT".to_vec(), + b"USDT".to_vec(), + 12, + )); + + // Bob on parachain B has 0 USDT at this moment + assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &BOB), 0u128); + }); // send USDT token from parachainA to parachainB ParaA::execute_with(|| { + // Alice transfer USDT token from parachain A to Bob on parachain B assert_ok!(BridgeImpl::::transfer( ALICE.into(), - (Concrete(UsdtLocation::get()), Fungible(10u128)).into(), + (Concrete(UsdtLocation::get()), Fungible(100_000_000u128 - 4u128)).into(), MultiLocation::new( 1, X2( @@ -512,11 +697,15 @@ pub mod pallet { ), ) )); - assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &ALICE), ENDOWED_BALANCE - 10); + // Alice has 0 USDT now + assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &ALICE), 0u128); assert_events(vec![RuntimeEvent::SygmaXcmBridge( SygmaXcmBridgeEvent::XCMTransferSend { - asset: Box::new((Concrete(UsdtLocation::get()), Fungible(10u128)).into()), + asset: Box::new( + (Concrete(UsdtLocation::get()), Fungible(100_000_000u128 - 4u128)) + .into(), + ), origin: Box::new( Junction::AccountId32 { network: None, id: ALICE.into() }.into(), ), @@ -531,8 +720,27 @@ pub mod pallet { )]); }); + ParaC::execute_with(|| { + // on C, the sibling_account of parachain A will be withdrawn the same amount of Parachain C native assets + assert_eq!( + ParaBalances::free_balance(sibling_account(1)), + 1_000_000_000_000_000_u128 - (100_000_000u128 - 4u128) + ); + + // on C, the sibling_account of parachain B will be deposited the same amount of Parachain C native assets - xcm fee + assert_eq!( + ParaBalances::free_balance(sibling_account(2)), + (100_000_000u128 - 4u128) - 4u128 + ); + }); + + // Bob on Parachain B has USDT token now ParaB::execute_with(|| { - assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &BOB), 10); + // transferred amount from parachain is (100_000_000u128 - 4u128) minus the xcm fee twice on the reserved chain and the dest chain + assert_eq!( + ParaAssets::balance(UsdtAssetId::get(), &BOB), + 100_000_000u128 - 4u128 - 4u128 * 2 + ); }); } } diff --git a/xcm-bridge/src/mock/mod.rs b/xcm-bridge/src/mock/mod.rs index c88fc221..510d435e 100644 --- a/xcm-bridge/src/mock/mod.rs +++ b/xcm-bridge/src/mock/mod.rs @@ -12,6 +12,7 @@ pub mod relay; pub const ALICE: AccountId32 = AccountId32::new([0u8; 32]); pub const BOB: AccountId32 = AccountId32::new([1u8; 32]); +pub const ASSET_OWNER: AccountId32 = AccountId32::new([2u8; 32]); pub const ENDOWED_BALANCE: u128 = 100_000_000_000_000_000_000; pub type ParaBalances = pallet_balances::Pallet; @@ -35,6 +36,15 @@ decl_test_parachain! { } } +decl_test_parachain! { + pub struct ParaC { + Runtime = para::Runtime, + XcmpMessageHandler = para::XcmpQueue, + DmpMessageHandler = para::DmpQueue, + new_ext = para_ext(2005), // for USDT + } +} + decl_test_relay_chain! { pub struct Relay { Runtime = relay::Runtime, @@ -53,6 +63,7 @@ decl_test_network! { parachains = vec![ (1, ParaA), (2, ParaB), + (2005, ParaC), ], } } @@ -68,18 +79,13 @@ pub fn para_ext(para_id: u32) -> TestExternalities { }; parachain_info_config.assimilate_storage(&mut t).unwrap(); - // set Alice and Bob with ENDOWED_BALANCE amount of native asset on every parachain + // set Alice, Bob and ASSET_OWNER with ENDOWED_BALANCE amount of native asset on every parachain pallet_balances::GenesisConfig:: { - balances: vec![(ALICE, ENDOWED_BALANCE), (BOB, ENDOWED_BALANCE)], - } - .assimilate_storage(&mut t) - .unwrap(); - - // set Alice with ENDOWED_BALANCE amount of USDT asset on every parachain - pallet_assets::GenesisConfig:: { - assets: vec![(1, ALICE, false, 1)], - metadata: vec![(1, "USDT".into(), "USDT".into(), 6)], - accounts: vec![(1, ALICE, ENDOWED_BALANCE)], + balances: vec![ + (ALICE, ENDOWED_BALANCE), + (BOB, ENDOWED_BALANCE), + (ASSET_OWNER, ENDOWED_BALANCE), + ], } .assimilate_storage(&mut t) .unwrap(); diff --git a/xcm-bridge/src/mock/para.rs b/xcm-bridge/src/mock/para.rs index 494ec9d0..237e8b19 100644 --- a/xcm-bridge/src/mock/para.rs +++ b/xcm-bridge/src/mock/para.rs @@ -16,12 +16,10 @@ use polkadot_parachain_primitives::primitives::Sibling; use sp_core::{crypto::AccountId32, H256}; use sp_runtime::traits::{IdentityLookup, Zero}; use xcm::latest::{ - AssetId as XcmAssetId, InteriorMultiLocation, Junction, MultiAsset, MultiLocation, NetworkId, + AssetId as XcmAssetId, InteriorMultiLocation, MultiAsset, MultiLocation, NetworkId, Weight as XCMWeight, XcmContext, }; -use xcm::prelude::{ - Concrete, Fungible, GeneralKey, GlobalConsensus, Parachain, XcmError, X1, X2, X3, -}; +use xcm::prelude::{Concrete, Fungible, GlobalConsensus, Parachain, XcmError, X1, X2}; use xcm_builder::{ AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom, CurrencyAdapter, FixedWeightBounds, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking, ParentIsPreset, @@ -142,6 +140,7 @@ impl sygma_xcm_bridge::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Weigher = FixedWeightBounds; type XcmExecutor = XcmExecutor; + type AssetReservedChecker = sygma_bridge_forwarder::NativeAssetTypeIdentifier; type UniversalLocation = UniversalLocation; type SelfLocation = SelfLocation; type MinXcmFee = MinXcmFee; @@ -213,15 +212,17 @@ parameter_types! { parameter_types! { pub NativeLocation: MultiLocation = MultiLocation::here(); + pub NativeAssetId: AssetId = 0; // native asset ID is used for token registration on other parachain as foreign asset + pub PAALocation: MultiLocation = MultiLocation::new(1, X1(Parachain(1u32))); + pub PBALocation: MultiLocation = MultiLocation::new(1, X1(Parachain(2u32))); pub UsdtAssetId: AssetId = 1; pub UsdtLocation: MultiLocation = MultiLocation::new( 1, - X3( + X1( Parachain(2005), - slice_to_generalkey(b"sygma"), - slice_to_generalkey(b"usdt"), ), ); + // Parachain A and Parachain B native asset multilocation pub CheckingAccount: AccountId32 = AccountId32::new([102u8; 32]); } @@ -229,7 +230,8 @@ parameter_types! { pub SelfLocation: MultiLocation = MultiLocation::new(1, X1(Parachain(ParachainInfo::parachain_id().into()))); pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())); - pub MinXcmFee: Vec<(XcmAssetId, u128)> = vec![(NativeLocation::get().into(), 1_000_000_000_000u128), (UsdtLocation::get().into(), 1_000_000u128)]; + // set 1 token as min fee + pub MinXcmFee: Vec<(XcmAssetId, u128)> = vec![(NativeLocation::get().into(), 1_000_000_000_000u128), (PBALocation::get().into(), 1_000_000_000_000u128), (UsdtLocation::get().into(), 1_000_000u128)]; } pub struct SimpleForeignAssetConverter(PhantomData<()>); @@ -239,6 +241,8 @@ impl MatchesFungibles for SimpleForeignAssetConverter { (Fungible(ref amount), Concrete(ref id)) => { if id == &UsdtLocation::get() { Ok((UsdtAssetId::get(), *amount)) + } else if id == &PBALocation::get() || id == &PAALocation::get() { + Ok((NativeAssetId::get(), *amount)) } else { Err(ExecutionError::AssetNotHandled) } @@ -356,16 +360,3 @@ pub fn assert_events(mut expected: Vec) { assert_eq!(next, evt, "Events don't match"); } } - -pub fn slice_to_generalkey(key: &[u8]) -> Junction { - let len = key.len(); - assert!(len <= 32); - GeneralKey { - length: len as u8, - data: { - let mut data = [0u8; 32]; - data[..len].copy_from_slice(key); - data - }, - } -} From 21beac310eb619deb9e7e0d57a4d4201eddcf8f6 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Tue, 30 Jan 2024 11:40:13 -0500 Subject: [PATCH 28/30] add xcm weight --- bridge-forwarder/src/lib.rs | 5 +++-- bridge-forwarder/src/mock.rs | 8 +++++++- bridge/src/lib.rs | 10 +++++++--- traits/src/lib.rs | 7 ++++++- xcm-bridge/src/lib.rs | 25 +++++++++++++++++-------- 5 files changed, 40 insertions(+), 15 deletions(-) diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index d4527075..62a4d6be 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -45,7 +45,8 @@ pub mod pallet { what: MultiAsset, dest: MultiLocation, ) -> DispatchResult { - T::XCMBridge::transfer(origin, what.clone(), dest)?; + let cap_weight: Weight = Weight::from_parts(6_000_000_000u64, 2_000_000u64); + T::XCMBridge::transfer(origin, what.clone(), dest, Some(cap_weight))?; let origin_location: MultiLocation = Junction::AccountId32 { network: None, id: origin }.into(); @@ -64,7 +65,7 @@ pub mod pallet { what: MultiAsset, dest: MultiLocation, ) -> DispatchResult { - T::SygmaBridge::transfer(origin, what.clone(), dest)?; + T::SygmaBridge::transfer(origin, what.clone(), dest, None)?; let origin_location: MultiLocation = Junction::AccountId32 { network: None, id: origin }.into(); diff --git a/bridge-forwarder/src/mock.rs b/bridge-forwarder/src/mock.rs index e578f2e5..4cc55c2a 100644 --- a/bridge-forwarder/src/mock.rs +++ b/bridge-forwarder/src/mock.rs @@ -19,6 +19,7 @@ use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; use sp_runtime::{AccountId32, BuildStorage}; use xcm::latest::{BodyId, Junction, MultiAsset, MultiLocation, NetworkId}; use xcm::prelude::{Concrete, Fungible, GeneralKey, Parachain, X3}; +use xcm::v3::Weight; use xcm_builder::{ AccountId32Aliases, CurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, ParentIsPreset, SiblingParachainConvertsVia, @@ -149,7 +150,12 @@ impl sygma_bridge_forwarder::Config for Runtime { pub struct BridgeImplRuntime(PhantomData); impl Bridge for BridgeImplRuntime { - fn transfer(_sender: [u8; 32], _asset: MultiAsset, _dest: MultiLocation) -> DispatchResult { + fn transfer( + _sender: [u8; 32], + _asset: MultiAsset, + _dest: MultiLocation, + _max_weight: Option, + ) -> DispatchResult { Ok(()) } } diff --git a/bridge/src/lib.rs b/bridge/src/lib.rs index ca28706d..ceb06a4d 100644 --- a/bridge/src/lib.rs +++ b/bridge/src/lib.rs @@ -688,10 +688,14 @@ pub mod pallet { where ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, { - fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult { + fn transfer( + sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation, + _max_weight: Option, + ) -> DispatchResult { let sender_origin = OriginFor::::from(RawOrigin::Signed(sender.into())); Pallet::::deposit(sender_origin, Box::from(asset), Box::from(dest))?; - Ok(()) } } @@ -1365,7 +1369,7 @@ pub mod pallet { }; // Call transfer instead of deposit - assert_ok!(SygmaBridge::transfer(ALICE.into(), asset.clone(), dest)); + assert_ok!(SygmaBridge::transfer(ALICE.into(), asset.clone(), dest, None)); // Check balances assert_eq!(Balances::free_balance(ALICE), ENDOWED_BALANCE - amount); diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 70855f46..43097c7c 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -82,7 +82,12 @@ pub trait TransactorForwarder { } pub trait Bridge { - fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult; + fn transfer( + sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation, + max_weight: Option, + ) -> DispatchResult; } pub trait AssetReserveLocationParser { diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index e1ee9502..2647b3ab 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -168,7 +168,6 @@ pub mod pallet { impl AssetReserveLocationParser for Pallet { fn reserved_location(asset: &MultiAsset) -> Option { let location = match (&asset.id, &asset.fun) { - // So far our native asset is concrete (Concrete(id), Fungible(_)) => Some(*id), _ => None, }; @@ -192,7 +191,12 @@ pub mod pallet { pub struct BridgeImpl(PhantomData); impl Bridge for BridgeImpl { - fn transfer(sender: [u8; 32], asset: MultiAsset, dest: MultiLocation) -> DispatchResult { + fn transfer( + sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation, + max_weight: Option, + ) -> DispatchResult { let origin_location: MultiLocation = Junction::AccountId32 { network: None, id: sender }.into(); @@ -220,7 +224,7 @@ pub mod pallet { origin: origin_location, dest: dest_location, recipient, - weight: XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64), // TODO: configure weight + weight: max_weight.unwrap_or(XCMWeight::from_parts(6_000_000_000u64, 2_000_000u64)), _unused: PhantomData, }; @@ -440,7 +444,8 @@ pub mod pallet { Parachain(2u32), Junction::AccountId32 { network: None, id: BOB.into() }, ), - ) + ), + None )); // Alice should lost the amount of native asset of paraA @@ -515,7 +520,8 @@ pub mod pallet { Parachain(1u32), Junction::AccountId32 { network: None, id: ALICE.into() }, ), - ) + ), + None )); assert_eq!(ParaBalances::free_balance(&ALICE), ENDOWED_BALANCE - amount); assert_eq!(ParaBalances::free_balance(sibling_account(1)), amount); @@ -535,7 +541,8 @@ pub mod pallet { Parachain(2u32), Junction::AccountId32 { network: None, id: BOB.into() } ) - ) + ), + None )); // now Alice holds 0 of PBA @@ -648,7 +655,8 @@ pub mod pallet { Parachain(1u32), Junction::AccountId32 { network: None, id: ALICE.into() }, ), - ) + ), + None )); assert_eq!( ParaAssets::balance(UsdtAssetId::get(), &ASSET_OWNER), @@ -695,7 +703,8 @@ pub mod pallet { Parachain(2u32), Junction::AccountId32 { network: None, id: BOB.into() }, ), - ) + ), + None )); // Alice has 0 USDT now assert_eq!(ParaAssets::balance(UsdtAssetId::get(), &ALICE), 0u128); From e59ed897e4f7051e0e2729fcc189549908fb32a7 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Wed, 31 Jan 2024 10:05:46 -0500 Subject: [PATCH 29/30] adjust the forwarder multilocaiton condition --- bridge-forwarder/src/lib.rs | 44 ++++++++++---------- bridge-forwarder/src/xcm_asset_transactor.rs | 16 +++---- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index 62a4d6be..0333ed0c 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -100,13 +100,11 @@ pub mod pallet { #[cfg(test)] mod test { use codec::Encode; - use frame_support::{ - assert_noop, assert_ok, traits::tokens::fungibles::Create as FungibleCerate, - }; + use frame_support::{assert_ok, traits::tokens::fungibles::Create as FungibleCerate}; use hex_literal::hex; use xcm::latest::{Junction, XcmContext}; use xcm::prelude::{ - AccountId32, Concrete, Fungible, GeneralKey, Here, Parachain, XcmError, X1, X2, X5, + AccountId32, Concrete, Fungible, GeneralKey, Here, Parachain, X1, X2, X3, X4, }; use xcm::v3::Junction::GeneralIndex; use xcm::v3::{MultiAsset, MultiLocation}; @@ -246,8 +244,7 @@ pub mod pallet { let dest_domain_id = 1; let outer_recipient: MultiLocation = MultiLocation::new( 1, - X5( - Parachain(1000), + X4( GeneralKey { length: 5, data: hex![ @@ -376,29 +373,30 @@ pub mod pallet { } #[test] - fn test_xcm_asset_transactor_not_supported_dest() { + fn test_xcm_asset_transactor_other_dest() { new_test_ext().execute_with(|| { - let none_supported_recipient: MultiLocation = MultiLocation::new( + let other_recipient: MultiLocation = MultiLocation::new( 2, - X2(Parachain(2005), slice_to_generalkey(b"substrate recipient")), + X3( + Parachain(2005), + slice_to_generalkey(b"substrate recipient"), + AccountId32 { network: None, id: BOB.into() }, + ), ); // send native asset to non-supported world let native_asset: MultiAsset = (Concrete(MultiLocation::new(0, Here)), Fungible(10u128)).into(); - assert_noop!( - XCMAssetTransactor::< - CurrencyTransactor, - FungiblesTransactor, - NativeAssetTypeIdentifier, - ForwarderImplRuntime, - >::deposit_asset( - &native_asset, - &none_supported_recipient, - &XcmContext::with_message_id([0; 32]) - ), - XcmError::DestinationUnsupported - ); + assert_ok!(XCMAssetTransactor::< + CurrencyTransactor, + FungiblesTransactor, + NativeAssetTypeIdentifier, + ForwarderImplRuntime, + >::deposit_asset( + &native_asset, + &other_recipient, + &XcmContext::with_message_id([0; 32]) + )); // asset tmp holder for substrate world and outer world transfer, should not receive any token let tmp_account_outer = sp_io::hashing::blake2_256( @@ -413,7 +411,7 @@ pub mod pallet { ); assert_eq!( Balances::free_balance(sp_runtime::AccountId32::from(tmp_account_substrate)), - 0u128 + 10u128 ); }) } diff --git a/bridge-forwarder/src/xcm_asset_transactor.rs b/bridge-forwarder/src/xcm_asset_transactor.rs index ae3e6c66..78b4b27a 100644 --- a/bridge-forwarder/src/xcm_asset_transactor.rs +++ b/bridge-forwarder/src/xcm_asset_transactor.rs @@ -38,13 +38,13 @@ impl< } }, // recipient is on the remote chain - (1, Some(Parachain(_))) => { + _ => { // 2. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet match who.interior { - // sygma: 7379676d61000000000000000000000000000000000000000000000000000000 + // sygma: 7379676d61000000000000000000000000000000000000000000000000000000 // sygma-bridge: 7379676d612d6272696467650000000000000000000000000000000000000000 - // outer world multilocation pattern: { Parachain(1000), GeneralKey { length: 5, data: b"sygma"}, GeneralKey { length: 12, data: b"sygma-bridge"}, GeneralIndex(domainID), GeneralKey { length: length_of_recipient_address, data: recipient_address} } - X5(Parachain(1000), GeneralKey { length: 5, data: hex!["7379676d61000000000000000000000000000000000000000000000000000000"]}, GeneralKey { length: 12, data: hex!["7379676d612d6272696467650000000000000000000000000000000000000000"]}, GeneralIndex(..), GeneralKey { .. }) => { + // outer world multilocation pattern: { Parachain(X), GeneralKey { length: 5, data: b"sygma"}, GeneralKey { length: 12, data: b"sygma-bridge"}, GeneralIndex(domainID), GeneralKey { length: length_of_recipient_address, data: recipient_address} } + X4(GeneralKey { length: 5, data: hex!["7379676d61000000000000000000000000000000000000000000000000000000"]}, GeneralKey { length: 12, data: hex!["7379676d612d6272696467650000000000000000000000000000000000000000"]}, GeneralIndex(..), GeneralKey { .. }) => { // check if the asset is native or foreign, and deposit the asset to a tmp account first let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey { length: 8, data: [1u8; 32] })).encode()); if AssetTypeChecker::is_native_asset(what) { @@ -55,9 +55,9 @@ impl< Forwarder::other_world_transactor_forwarder(tmp_account, what.clone(), *who).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; } + // 3. recipient is on remote parachain, will forward to xcm bridge pallet _ => { - // 3. recipient is on remote parachain - // xcm message must have a sender(origin), so a tmp account derived from pallet would be necessary here + // xcm message must have a sender(origin), so a tmp account derived from pallet would be necessary here let tmp_account = sp_io::hashing::blake2_256(&MultiLocation::new(0, X1(GeneralKey { length: 8, data: [2u8; 32] })).encode()); // check if the asset is native or foreign, and call the corresponding deposit_asset(), recipient will be the derived tmp account @@ -72,10 +72,6 @@ impl< } } }, - // Other destination multiLocation not supported, return Err - _ => { - return Err(XcmError::DestinationUnsupported); - }, } Ok(()) From 905412f165d331c8d507d5f315be26a14cfe8763 Mon Sep 17 00:00:00 2001 From: Freddy Li Date: Mon, 5 Feb 2024 15:47:10 -0500 Subject: [PATCH 30/30] pr comments fix --- bridge-forwarder/src/lib.rs | 34 ++++---------------- bridge-forwarder/src/mock.rs | 25 ++++++++++++-- bridge-forwarder/src/xcm_asset_transactor.rs | 2 +- xcm-bridge/src/lib.rs | 2 +- xcm-bridge/src/mock/para.rs | 25 ++++++++++++-- 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/bridge-forwarder/src/lib.rs b/bridge-forwarder/src/lib.rs index 0333ed0c..0e59926d 100644 --- a/bridge-forwarder/src/lib.rs +++ b/bridge-forwarder/src/lib.rs @@ -6,18 +6,16 @@ pub use self::pallet::*; #[cfg(test)] -mod mock; +pub mod mock; pub mod xcm_asset_transactor; #[frame_support::pallet] pub mod pallet { - use cumulus_primitives_core::ParaId; use frame_support::pallet_prelude::*; use frame_support::traits::StorageVersion; use xcm::latest::{Junction, MultiAsset, MultiLocation}; - use xcm::prelude::{Concrete, Fungible, Parachain, X1}; - use sygma_traits::{AssetTypeIdentifier, Bridge, TransactorForwarder}; + use sygma_traits::{Bridge, TransactorForwarder}; const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); @@ -80,23 +78,6 @@ pub mod pallet { } } - pub struct NativeAssetTypeIdentifier(PhantomData); - impl> AssetTypeIdentifier for NativeAssetTypeIdentifier { - /// check if the given MultiAsset is a native asset - fn is_native_asset(asset: &MultiAsset) -> bool { - // currently there are two multilocations are considered as native asset: - // 1. integrated parachain native asset(MultiLocation::here()) - // 2. other parachain native asset(MultiLocation::new(1, X1(Parachain(T::get().into())))) - let native_locations = - [MultiLocation::here(), MultiLocation::new(1, X1(Parachain(T::get().into())))]; - - match (&asset.id, &asset.fun) { - (Concrete(ref id), Fungible(_)) => native_locations.contains(id), - _ => false, - } - } - } - #[cfg(test)] mod test { use codec::Encode; @@ -114,14 +95,11 @@ pub mod pallet { use crate::mock::{ assert_events, new_test_ext, slice_to_generalkey, Assets, Balances, CurrencyTransactor, - ForwarderImplRuntime, FungiblesTransactor, ParachainInfo, Runtime, RuntimeEvent, - RuntimeOrigin, SygmaBridgeForwarder, UsdtAssetId, UsdtLocation, ALICE, ASSET_OWNER, - BOB, ENDOWED_BALANCE, - }; - use crate::{ - xcm_asset_transactor::XCMAssetTransactor, Event as SygmaBridgeForwarderEvent, - NativeAssetTypeIdentifier, + ForwarderImplRuntime, FungiblesTransactor, NativeAssetTypeIdentifier, ParachainInfo, + Runtime, RuntimeEvent, RuntimeOrigin, SygmaBridgeForwarder, UsdtAssetId, UsdtLocation, + ALICE, ASSET_OWNER, BOB, ENDOWED_BALANCE, }; + use crate::{xcm_asset_transactor::XCMAssetTransactor, Event as SygmaBridgeForwarderEvent}; #[test] fn test_xcm_transactor_forwarder() { diff --git a/bridge-forwarder/src/mock.rs b/bridge-forwarder/src/mock.rs index 4cc55c2a..80025e77 100644 --- a/bridge-forwarder/src/mock.rs +++ b/bridge-forwarder/src/mock.rs @@ -3,10 +3,12 @@ #![cfg(test)] +use cumulus_primitives_core::ParaId; use std::marker::PhantomData; use std::result; use frame_support::dispatch::DispatchResult; +use frame_support::pallet_prelude::Get; use frame_support::{ construct_runtime, parameter_types, traits::{AsEnsureOriginWithArg, ConstU32}, @@ -18,7 +20,7 @@ use sp_runtime::testing::H256; use sp_runtime::traits::{BlakeTwo256, IdentityLookup}; use sp_runtime::{AccountId32, BuildStorage}; use xcm::latest::{BodyId, Junction, MultiAsset, MultiLocation, NetworkId}; -use xcm::prelude::{Concrete, Fungible, GeneralKey, Parachain, X3}; +use xcm::prelude::{Concrete, Fungible, GeneralKey, Parachain, X1, X3}; use xcm::v3::Weight; use xcm_builder::{ AccountId32Aliases, CurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, ParentIsPreset, @@ -26,7 +28,7 @@ use xcm_builder::{ }; use xcm_executor::traits::{Error as ExecutionError, MatchesFungibles}; -use sygma_traits::{Bridge, TransactorForwarder}; +use sygma_traits::{AssetTypeIdentifier, Bridge, TransactorForwarder}; use crate as sygma_bridge_forwarder; @@ -260,6 +262,25 @@ impl MatchesFungibles for SimpleForeignAssetConverter { } } +/// NativeAssetTypeIdentifier impl AssetTypeIdentifier for XCMAssetTransactor +/// This impl is only for local mock purpose, the integrated parachain might have their own version +pub struct NativeAssetTypeIdentifier(PhantomData); +impl> AssetTypeIdentifier for NativeAssetTypeIdentifier { + /// check if the given MultiAsset is a native asset + fn is_native_asset(asset: &MultiAsset) -> bool { + // currently there are two multilocations are considered as native asset: + // 1. integrated parachain native asset(MultiLocation::here()) + // 2. other parachain native asset(MultiLocation::new(1, X1(Parachain(T::get().into())))) + let native_locations = + [MultiLocation::here(), MultiLocation::new(1, X1(Parachain(T::get().into())))]; + + match (&asset.id, &asset.fun) { + (Concrete(ref id), Fungible(_)) => native_locations.contains(id), + _ => false, + } + } +} + pub fn slice_to_generalkey(key: &[u8]) -> Junction { let len = key.len(); assert!(len <= 32); diff --git a/bridge-forwarder/src/xcm_asset_transactor.rs b/bridge-forwarder/src/xcm_asset_transactor.rs index 78b4b27a..3ec294e8 100644 --- a/bridge-forwarder/src/xcm_asset_transactor.rs +++ b/bridge-forwarder/src/xcm_asset_transactor.rs @@ -29,7 +29,7 @@ impl< fn deposit_asset(what: &MultiAsset, who: &MultiLocation, context: &XcmContext) -> XcmResult { match (who.parents, who.first_interior()) { // 1. recipient is on the local parachain - (0, Some(AccountId32 { .. })) => { + (0, Some(AccountId32 { .. })) | (0, Some(AccountKey20 { .. })) => { // check if the asset is native, and call the corresponding deposit_asset() if AssetTypeChecker::is_native_asset(what) { CurrencyTransactor::deposit_asset(what, who, context)?; diff --git a/xcm-bridge/src/lib.rs b/xcm-bridge/src/lib.rs index 2647b3ab..1b9e52bc 100644 --- a/xcm-bridge/src/lib.rs +++ b/xcm-bridge/src/lib.rs @@ -570,7 +570,7 @@ pub mod pallet { ParaB::execute_with(|| { // Bob should get amount - fee * 2 bcs there are two times of xcm transfer assert_eq!(ParaBalances::free_balance(&BOB), ENDOWED_BALANCE + amount - fee * 2); - assert_eq!(ParaBalances::free_balance(sibling_account(1)), 4u128); + assert_eq!(ParaBalances::free_balance(sibling_account(1)), amount - (amount - fee)); }); } diff --git a/xcm-bridge/src/mock/para.rs b/xcm-bridge/src/mock/para.rs index 237e8b19..7c470d9b 100644 --- a/xcm-bridge/src/mock/para.rs +++ b/xcm-bridge/src/mock/para.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use std::result; use cumulus_primitives_core::{ChannelStatus, GetChannelInfo, ParaId, Weight}; +use frame_support::pallet_prelude::Get; use frame_support::traits::{ConstU16, ConstU64, Nothing}; use frame_support::{ construct_runtime, parameter_types, @@ -15,6 +16,7 @@ use frame_system::EnsureRoot; use polkadot_parachain_primitives::primitives::Sibling; use sp_core::{crypto::AccountId32, H256}; use sp_runtime::traits::{IdentityLookup, Zero}; +use sygma_traits::AssetTypeIdentifier; use xcm::latest::{ AssetId as XcmAssetId, InteriorMultiLocation, MultiAsset, MultiLocation, NetworkId, Weight as XCMWeight, XcmContext, @@ -31,8 +33,6 @@ use xcm_executor::{ Assets as XcmAssets, Config, XcmExecutor, }; -use sygma_bridge_forwarder; - use crate as sygma_xcm_bridge; use crate::BridgeImpl; @@ -140,7 +140,7 @@ impl sygma_xcm_bridge::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Weigher = FixedWeightBounds; type XcmExecutor = XcmExecutor; - type AssetReservedChecker = sygma_bridge_forwarder::NativeAssetTypeIdentifier; + type AssetReservedChecker = NativeAssetTypeIdentifier; type UniversalLocation = UniversalLocation; type SelfLocation = SelfLocation; type MinXcmFee = MinXcmFee; @@ -281,6 +281,25 @@ pub type FungiblesTransactor = FungiblesAdapter< CheckingAccount, >; +/// NativeAssetTypeIdentifier impl AssetTypeIdentifier for XCMAssetTransactor +/// This impl is only for local mock purpose, the integrated parachain might have their own version +pub struct NativeAssetTypeIdentifier(PhantomData); +impl> AssetTypeIdentifier for NativeAssetTypeIdentifier { + /// check if the given MultiAsset is a native asset + fn is_native_asset(asset: &MultiAsset) -> bool { + // currently there are two multilocations are considered as native asset: + // 1. integrated parachain native asset(MultiLocation::here()) + // 2. other parachain native asset(MultiLocation::new(1, X1(Parachain(T::get().into())))) + let native_locations = + [MultiLocation::here(), MultiLocation::new(1, X1(Parachain(T::get().into())))]; + + match (&asset.id, &asset.fun) { + (Concrete(ref id), Fungible(_)) => native_locations.contains(id), + _ => false, + } + } +} + pub struct ChannelInfo; impl GetChannelInfo for ChannelInfo {