diff --git a/Cargo.lock b/Cargo.lock index 84d8d4a0..f1dae67f 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", @@ -580,7 +580,7 @@ dependencies = [ "log", "parking", "polling", - "rustix 0.37.26", + "rustix 0.37.27", "slab", "socket2 0.4.10", "waker-fn", @@ -603,7 +603,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -614,7 +614,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -767,7 +767,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1191,7 +1191,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -1278,9 +1278,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", ] @@ -1344,9 +1344,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", ] @@ -1460,9 +1460,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" @@ -1499,12 +1499,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -1585,6 +1582,60 @@ 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.2.0#63d7f90f778ae4aba0d82326cf7bba7087d96be4" +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-xcm" +version = "0.1.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.2.0#63d7f90f778ae4aba0d82326cf7bba7087d96be4" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "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.2.0#63d7f90f778ae4aba0d82326cf7bba7087d96be4" +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" @@ -1665,20 +1716,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", @@ -1688,9 +1739,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", @@ -1698,24 +1749,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]] @@ -1989,7 +2040,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2011,18 +2062,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", @@ -2030,7 +2081,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.38", + "syn 2.0.39", "termcolor", "toml 0.7.8", "walkdir", @@ -2071,9 +2122,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" @@ -2212,7 +2263,17 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "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]] @@ -2228,6 +2289,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" @@ -2312,7 +2386,7 @@ dependencies = [ "fs-err", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2374,7 +2448,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", @@ -2386,9 +2460,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" @@ -2396,7 +2470,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", ] @@ -2588,7 +2662,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2715,7 +2789,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2727,7 +2801,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -2737,7 +2811,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]] @@ -2825,9 +2899,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", @@ -2840,9 +2914,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", @@ -2850,15 +2924,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", @@ -2868,9 +2942,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" @@ -2889,13 +2963,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]] @@ -2911,15 +2985,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" @@ -2929,9 +3003,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", @@ -3346,9 +3420,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", @@ -3358,7 +3432,7 @@ dependencies = [ "rustls-native-certs", "tokio", "tokio-rustls", - "webpki-roots 0.23.1", + "webpki-roots 0.25.2", ] [[package]] @@ -3501,9 +3575,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", @@ -3610,7 +3684,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", ] @@ -3640,9 +3714,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", ] @@ -3874,9 +3948,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" @@ -4313,6 +4387,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" @@ -4510,7 +4595,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4524,7 +4609,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4535,7 +4620,7 @@ checksum = "d710e1214dffbab3b5dacb21475dde7d6ed84c69ff722b3a47a782668d44fbac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4546,7 +4631,7 @@ checksum = "b8fb85ec1620619edf2984a7693497d4ec88a9665d8b87e942856884c92dbf2a" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -4608,7 +4693,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]] @@ -4782,9 +4867,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", @@ -5649,6 +5734,27 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-xcm" +version = "1.0.0" +source = "git+https://github.com/paritytech/polkadot-sdk.git?branch=release-polkadot-v1.2.0#63d7f90f778ae4aba0d82326cf7bba7087d96be4" +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" @@ -5889,7 +5995,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5910,7 +6016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.2", + "indexmap 2.1.0", ] [[package]] @@ -5930,7 +6036,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -5979,9 +6085,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" @@ -6209,9 +6315,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" @@ -6272,7 +6378,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]] @@ -6290,12 +6396,12 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ - "thiserror", - "toml 0.5.11", + "once_cell", + "toml_edit", ] [[package]] @@ -6330,7 +6436,7 @@ checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -6376,7 +6482,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -6674,12 +6780,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", ] @@ -6700,7 +6806,7 @@ checksum = "7f7473c2cfcf90008193dd0e3e16599455cb601a9fce322b5bb55de799664925" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -6967,9 +7073,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", @@ -6981,9 +7087,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", @@ -6995,9 +7101,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", @@ -7039,7 +7145,7 @@ checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" dependencies = [ "log", "ring 0.17.5", - "rustls-webpki 0.101.7", + "rustls-webpki", "sct 0.7.1", ] @@ -7064,16 +7170,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" @@ -7210,7 +7306,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -7466,7 +7562,7 @@ dependencies = [ "cfg-if", "libc", "log", - "rustix 0.36.16", + "rustix 0.36.17", "sc-allocator", "sc-executor-common", "sp-runtime-interface", @@ -7978,7 +8074,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -8259,29 +8355,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", @@ -8555,7 +8651,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -8774,7 +8870,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]] @@ -8793,7 +8889,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]] @@ -8992,7 +9088,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9184,7 +9280,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9416,7 +9512,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9440,9 +9536,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", @@ -9575,6 +9671,9 @@ dependencies = [ "arrayref", "assert_matches", "bounded-collections", + "cumulus-pallet-xcm", + "cumulus-primitives-core", + "cumulus-primitives-utility", "ethabi", "fixed", "frame-benchmarking", @@ -9602,9 +9701,37 @@ 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]] +name = "sygma-bridge-forwarder" +version = "0.3.0" +dependencies = [ + "cumulus-pallet-xcm", + "cumulus-primitives-core", + "cumulus-primitives-utility", + "frame-support", + "frame-system", + "hex-literal 0.3.4", + "pallet-assets", + "pallet-balances", + "pallet-parachain-info", + "pallet-timestamp", + "parity-scale-codec", + "polkadot-parachain-primitives", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "sygma-traits", ] [[package]] @@ -9688,6 +9815,42 @@ dependencies = [ "staging-xcm-builder", ] +[[package]] +name = "sygma-xcm-bridge" +version = "0.3.0" +dependencies = [ + "cumulus-pallet-dmp-queue", + "cumulus-pallet-xcm", + "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", + "pallet-parachain-info", + "pallet-xcm", + "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "sygma-bridge-forwarder", + "sygma-traits", + "xcm-simulator", +] + [[package]] name = "syn" version = "1.0.109" @@ -9701,9 +9864,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", @@ -9757,14 +9920,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", ] @@ -9800,7 +9963,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -9947,7 +10110,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -10034,7 +10197,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", @@ -10102,7 +10265,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -10515,9 +10678,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", @@ -10525,24 +10688,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", @@ -10552,9 +10715,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", @@ -10562,22 +10725,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" @@ -10702,7 +10865,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", @@ -10798,7 +10961,7 @@ checksum = "6e0554b84c15a27d76281d06838aed94e13a77d7bf604bbbaf548aa20eb93846" dependencies = [ "object 0.30.4", "once_cell", - "rustix 0.36.16", + "rustix 0.36.17", ] [[package]] @@ -10829,7 +10992,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", @@ -10850,9 +11013,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", @@ -10887,15 +11050,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" @@ -11133,7 +11287,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.20", + "rustix 0.38.21", ] [[package]] @@ -11336,9 +11490,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", ] @@ -11430,7 +11584,25 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.38", + "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.2.0#63d7f90f778ae4aba0d82326cf7bba7087d96be4" +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]] @@ -11458,22 +11630,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]] @@ -11493,7 +11665,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..dd190f14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ members = [ "substrate-node/node", "substrate-node/runtime", "parachain-info", + "bridge-forwarder", + "xcm-bridge" ] exclude = [ diff --git a/bridge-forwarder/Cargo.toml b/bridge-forwarder/Cargo.toml new file mode 100644 index 00000000..c65c7a64 --- /dev/null +++ b/bridge-forwarder/Cargo.toml @@ -0,0 +1,71 @@ +[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"] } +hex-literal = { version = "0.3", default-features = false } + +# Substrate +frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } + +# Polkadot +xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } + +# Cumulus +cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.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.2.0" } +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +pallet-timestamp = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } + +# Polkadot +polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } + +# Local +sygma-traits = { path = "../traits" } +pallet-parachain-info = { path = "../parachain-info" } + +[features] +default = ["std"] +std = [ + "codec/std", + "scale-info/std", + "frame-support/std", + "frame-system/std", + "sp-std/std", + "sp-io/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 = [ + '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..0e59926d --- /dev/null +++ b/bridge-forwarder/src/lib.rs @@ -0,0 +1,440 @@ +// 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::*; + +#[cfg(test)] +pub mod mock; +pub mod xcm_asset_transactor; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_support::traits::StorageVersion; + use xcm::latest::{Junction, MultiAsset, MultiLocation}; + + use sygma_traits::{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 { + 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(); + + 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, None)?; + + let origin_location: MultiLocation = + Junction::AccountId32 { network: None, id: origin }.into(); + + Pallet::::deposit_event(Event::OtherWorldTransferForward { + asset: what, + origin: origin_location, + dest, + }); + + Ok(()) + } + } + + #[cfg(test)] + mod test { + use codec::Encode; + 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, X1, X2, X3, X4, + }; + 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, slice_to_generalkey, Assets, Balances, CurrencyTransactor, + 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() { + 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); + + // 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(); + 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); + }) + } + + #[test] + fn test_xcm_asset_transactor_outer() { + new_test_ext().execute_with(|| { + let dest_domain_id = 1; + let outer_recipient: MultiLocation = MultiLocation::new( + 1, + X4( + 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_other_dest() { + new_test_ext().execute_with(|| { + let other_recipient: MultiLocation = MultiLocation::new( + 2, + 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_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( + &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)), + 10u128 + ); + }) + } + + #[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/mock.rs b/bridge-forwarder/src/mock.rs new file mode 100644 index 00000000..80025e77 --- /dev/null +++ b/bridge-forwarder/src/mock.rs @@ -0,0 +1,315 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +#![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}, +}; +use frame_system as system; +use frame_system::EnsureSigned; +use polkadot_parachain_primitives::primitives::Sibling; +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, X1, X3}; +use xcm::v3::Weight; +use xcm_builder::{ + AccountId32Aliases, CurrencyAdapter, FungiblesAdapter, IsConcrete, NoChecking, ParentIsPreset, + SiblingParachainConvertsVia, +}; +use xcm_executor::traits::{Error as ExecutionError, MatchesFungibles}; + +use sygma_traits::{AssetTypeIdentifier, Bridge, TransactorForwarder}; + +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, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + SygmaBridgeForwarder: sygma_bridge_forwarder::{Pallet, Event}, + 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 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>; +} + +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 RuntimeHoldReason = (); + type MaxHolds = ConstU32<1>; + type MaxFreezes = ConstU32<1>; +} + +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 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 = (); +} + +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; +} + +pub struct BridgeImplRuntime(PhantomData); +impl Bridge for BridgeImplRuntime { + fn transfer( + _sender: [u8; 32], + _asset: MultiAsset, + _dest: MultiLocation, + _max_weight: Option, + ) -> 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)], + } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} + +#[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"); + } +} + +// 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]); + + 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), + } + } +} + +/// 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); + 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 new file mode 100644 index 00000000..3ec294e8 --- /dev/null +++ b/bridge-forwarder/src/xcm_asset_transactor.rs @@ -0,0 +1,93 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +use core::marker::PhantomData; + +use codec::Encode; +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< + 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 { .. })) | (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)?; + } else { + FungiblesTransactor::deposit_asset(what, who, context)? + } + }, + // recipient is on the remote chain + _ => { + // 2. recipient is on non-substrate chain(evm, cosmos, etc.), will forward to sygma bridge pallet + match who.interior { + // sygma: 7379676d61000000000000000000000000000000000000000000000000000000 + // sygma-bridge: 7379676d612d6272696467650000000000000000000000000000000000000000 + // 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) { + 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::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 + _ => { + // 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 + // 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).map_err(|e| XcmError::FailedToTransactAsset(e.into()))?; + } + } + }, + } + + 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)? + }; + + Ok(assets) + } +} diff --git a/bridge/Cargo.toml b/bridge/Cargo.toml index ab53f863..402b7ca0 100644 --- a/bridge/Cargo.toml +++ b/bridge/Cargo.toml @@ -34,11 +34,19 @@ 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.2.0", default-features = false } xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +# Cumulus +cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.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 } 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" @@ -62,6 +70,7 @@ polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot- parachains-common = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +# Local sygma-basic-feehandler = { path = "../basic-fee-handler" } sygma-traits = { path = "../traits" } @@ -88,6 +97,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", @@ -98,5 +110,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/lib.rs b/bridge/src/lib.rs index 2e943d9f..ceb06a4d 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; @@ -24,16 +25,15 @@ mod mock; #[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::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; @@ -42,17 +42,19 @@ pub mod pallet { 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 crate::eip712; - use sp_std::collections::btree_map::BTreeMap; use sygma_traits::{ - ChainID, DecimalConverter, DepositNonce, DomainID, ExtractDestinationData, FeeHandler, - MpcAddress, ResourceId, TransferType, VerifyingContractAddress, + 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); @@ -284,7 +286,7 @@ pub mod pallet { { /// Pause bridge, this would lead to bridge transfer failure before it being unpaused. #[pallet::call_index(0)] - #[pallet::weight(::WeightInfo::pause_bridge())] + #[pallet::weight(< T as Config >::WeightInfo::pause_bridge())] pub fn pause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { ensure!( >::has_access( @@ -306,7 +308,7 @@ pub mod pallet { /// Unpause bridge. #[pallet::call_index(1)] - #[pallet::weight(::WeightInfo::unpause_bridge())] + #[pallet::weight(< T as Config >::WeightInfo::unpause_bridge())] pub fn unpause_bridge(origin: OriginFor, dest_domain_id: DomainID) -> DispatchResult { ensure!( >::has_access( @@ -331,7 +333,7 @@ pub mod pallet { /// Mark an ECDSA address as a MPC account. #[pallet::call_index(2)] - #[pallet::weight(::WeightInfo::set_mpc_address())] + #[pallet::weight(< T as Config >::WeightInfo::set_mpc_address())] pub fn set_mpc_address(origin: OriginFor, addr: MpcAddress) -> DispatchResult { ensure!( >::has_access( @@ -355,7 +357,7 @@ pub mod pallet { /// Mark the give dest domainID with chainID to be enabled #[pallet::call_index(3)] - #[pallet::weight(::WeightInfo::register_domain())] + #[pallet::weight(< T as Config >::WeightInfo::register_domain())] pub fn register_domain( origin: OriginFor, dest_domain_id: DomainID, @@ -388,7 +390,7 @@ pub mod pallet { /// Mark the give dest domainID with chainID to be disabled #[pallet::call_index(4)] - #[pallet::weight(::WeightInfo::unregister_domain())] + #[pallet::weight(< T as Config >::WeightInfo::unregister_domain())] pub fn unregister_domain( origin: OriginFor, dest_domain_id: DomainID, @@ -430,7 +432,7 @@ pub mod pallet { /// Initiates a transfer. #[transactional] #[pallet::call_index(5)] - #[pallet::weight(::WeightInfo::deposit())] + #[pallet::weight(< T as Config >::WeightInfo::deposit())] pub fn deposit( origin: OriginFor, asset: Box, @@ -532,7 +534,7 @@ pub mod pallet { /// 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())] + #[pallet::weight(< T as Config >::WeightInfo::retry())] pub fn retry( origin: OriginFor, deposit_on_block_height: u128, @@ -566,7 +568,7 @@ pub mod pallet { /// 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))] + #[pallet::weight(< T as Config >::WeightInfo::execute_proposal(proposals.len() as u32))] pub fn execute_proposal( _origin: OriginFor, proposals: Vec, @@ -628,7 +630,7 @@ pub mod pallet { /// Pause all registered bridges #[pallet::call_index(8)] - #[pallet::weight(::WeightInfo::pause_all_bridges())] + #[pallet::weight(< T as Config >::WeightInfo::pause_all_bridges())] pub fn pause_all_bridges(origin: OriginFor) -> DispatchResult { ensure!( >::has_access( @@ -654,7 +656,7 @@ pub mod pallet { /// Unpause all registered bridges #[pallet::call_index(9)] - #[pallet::weight(::WeightInfo::unpause_all_bridges())] + #[pallet::weight(< T as Config >::WeightInfo::unpause_all_bridges())] pub fn unpause_all_bridges(origin: OriginFor) -> DispatchResult { ensure!( >::has_access( @@ -682,6 +684,22 @@ pub mod pallet { } } + impl Bridge for Pallet + where + ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, + { + 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(()) + } + } + impl Pallet where ::AccountId: From<[u8; 32]> + Into<[u8; 32]>, @@ -724,9 +742,9 @@ pub mod pallet { /// 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(), - ); + "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(), @@ -932,20 +950,6 @@ pub mod pallet { #[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, @@ -955,10 +959,26 @@ pub mod pallet { 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::*; + 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(|| { @@ -1312,6 +1332,80 @@ pub mod pallet { }) } + #[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, None)); + + // 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(|| { @@ -1319,7 +1413,7 @@ pub mod pallet { 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 + 0, 0, 0, 0, 0, 0, 100, ] ); let recipient = String::from("0x95ECF5ae000e0fe0e0dE63aDE9b7D82a372038b4"); @@ -1327,7 +1421,7 @@ pub mod pallet { 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 + 0, 0, 0, 0, 0, 0, 42, ] ); }) @@ -1347,7 +1441,7 @@ pub mod pallet { 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 + 97, 68, 69, 57, 98, 55, 68, 56, 50, 97, 51, 55, 50, 48, 51, 56, 98, 52, ] ); }) @@ -1413,7 +1507,7 @@ pub mod pallet { AccountId::new( SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) .unwrap() - ) + ), ), amount - fee ); @@ -1810,7 +1904,7 @@ pub mod pallet { AccountId::new( SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) .unwrap() - ) + ), ), 400_000_000_000_000 ); @@ -1927,7 +2021,7 @@ pub mod pallet { assert_eq!(Assets::balance(UsdtAssetId::get(), &BOB), 0); assert!(SygmaBridge::verify_by_mpc_address( final_message, - proposals_with_valid_signature.encode() + proposals_with_valid_signature.encode(), )); assert_ok!(SygmaBridge::execute_proposal( Origin::signed(ALICE), @@ -1956,7 +2050,7 @@ pub mod pallet { AccountId::new( SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) .unwrap() - ) + ), ), 200_000_000_000_000 ); @@ -2296,7 +2390,7 @@ pub mod pallet { AccountId::new( SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) .unwrap() - ) + ), ), 122_456_789_123_456_789_123 ); @@ -2369,7 +2463,7 @@ pub mod pallet { AccountId::new( SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) .unwrap() - ) + ), ), amount_astr_asset - fee_astr_asset ); @@ -2404,7 +2498,8 @@ pub mod pallet { // 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 + let fee_astr_asset_extreme_small_amount = 1; + // 0.000000000000000000000001 astr assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, @@ -2451,7 +2546,8 @@ pub mod pallet { 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 + let init_deposit = 10_000_000_000_000u128; + // 12 token in 12 decimal assert_ok!(SygmaBasicFeeHandler::set_fee( Origin::root(), DEST_DOMAIN_ID, @@ -2545,7 +2641,7 @@ pub mod pallet { AccountId::new( SygmaBridge::get_token_reserved_account(&UsdtLocation::get().into()) .unwrap() - ) + ), ), ENDOWED_BALANCE ); @@ -2600,7 +2696,7 @@ pub mod pallet { AccountId::new( SygmaBridge::get_token_reserved_account(&AstrLocation::get().into()) .unwrap() - ) + ), ), ENDOWED_BALANCE ); @@ -3082,7 +3178,8 @@ pub mod pallet { // 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 + let fee_upper_bound = 1_000_000_000_000_000u128; + // 1000 assert_ok!(SygmaPercentageFeeHandler::set_fee_rate( Origin::root(), DEST_DOMAIN_ID, diff --git a/bridge/src/mock.rs b/bridge/src/mock.rs index f149ed87..871c9c62 100644 --- a/bridge/src/mock.rs +++ b/bridge/src/mock.rs @@ -110,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/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 diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 60ea32cd..43097c7c 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; @@ -61,3 +62,34 @@ pub trait DecimalConverter { /// Sygma relayer will always send asset in 18 decimal fn convert_from(asset: &MultiAsset) -> Option; } + +// 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, + dest: MultiLocation, + ) -> DispatchResult; + fn other_world_transactor_forwarder( + sender: [u8; 32], + what: MultiAsset, + dest: MultiLocation, + ) -> DispatchResult; +} + +pub trait Bridge { + fn transfer( + sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation, + max_weight: Option, + ) -> DispatchResult; +} + +pub trait AssetReserveLocationParser { + fn reserved_location(asset: &MultiAsset) -> Option; +} diff --git a/xcm-bridge/Cargo.toml b/xcm-bridge/Cargo.toml new file mode 100644 index 00000000..505cc0cf --- /dev/null +++ b/xcm-bridge/Cargo.toml @@ -0,0 +1,96 @@ +[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.2.0", default-features = false } +frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +sp-std = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } + +# Polkadot +xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } + +# Cumulus +cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } +cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0", default-features = false } + +# 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 +sp-io = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +sp-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +sp-runtime = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +frame-support = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +frame-system = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +pallet-balances = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +pallet-assets = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +pallet-message-queue = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } + +# Polkadot +xcm = { package = "staging-xcm", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +xcm-executor = { package = "staging-xcm-executor", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +xcm-simulator = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +xcm-builder = { package = "staging-xcm-builder", git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +polkadot-parachain-primitives = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } + +# Cumulus +cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +cumulus-pallet-xcm = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } +cumulus-primitives-utility = { git = "https://github.com/paritytech/polkadot-sdk.git", branch = "release-polkadot-v1.2.0" } + +# Local +sygma-traits = { path = "../traits" } +pallet-parachain-info = { path = "../parachain-info" } + +env_logger = "0.11.1" + +[features] +default = ["std"] +std = [ + "codec/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", + "pallet-balances/std", + "pallet-assets/std", + "cumulus-primitives-core/std", + "cumulus-primitives-utility/std", + "cumulus-pallet-xcm/std", + "sygma-traits/std", + "sygma-bridge-forwarder/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..1b9e52bc --- /dev/null +++ b/xcm-bridge/src/lib.rs @@ -0,0 +1,756 @@ +// 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::*; + +#[cfg(test)] +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::{prelude::*, MultiLocation, Weight as XCMWeight}; + use xcm_executor::traits::WeightBounds; + + use sygma_traits::{AssetReserveLocationParser, AssetTypeIdentifier, 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 AssetReservedChecker: AssetTypeIdentifier; + + type UniversalLocation: Get; + + #[pallet::constant] + type SelfLocation: Get; + + /// Minimum xcm execution fee paid on destination chain. + 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, + /// 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, + AssetReservedLocationNotFound, + } + + #[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] + struct XcmObject { + asset: MultiAsset, + fee: MultiAsset, + origin: MultiLocation, + dest: MultiLocation, + recipient: MultiLocation, + weight: XCMWeight, + _unused: PhantomData, + } + + pub trait XcmHandler { + fn transfer_kind(&self, asset_reserved_location: MultiLocation) -> Option; + fn create_instructions(&self) -> Result, DispatchError>; + fn execute_instructions( + &self, + xcm_instructions: &mut Xcm, + ) -> DispatchResult; + } + + impl XcmHandler for XcmObject { + fn transfer_kind(&self, asset_reserved_location: MultiLocation) -> Option { + if T::AssetReservedChecker::is_native_asset(&self.asset.clone()) { + Some(TransferKind::SelfReserveAsset) + } else if asset_reserved_location == self.dest { + Some(TransferKind::ToReserve) + } else { + Some(TransferKind::ToNonReserve) + } + } + + fn create_instructions(&self) -> Result, DispatchError> { + 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()); + + 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(), + asset_reserved_location, + 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 { + let location = match (&asset.id, &asset.fun) { + (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, + } + }) + } + } + + pub struct BridgeImpl(PhantomData); + + impl Bridge for BridgeImpl { + fn transfer( + sender: [u8; 32], + asset: MultiAsset, + dest: MultiLocation, + max_weight: Option, + ) -> 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 min_fee_to_dest: MultiAsset = (asset.id, fee_per_asset).into(); + + let xcm = XcmObject:: { + asset: asset.clone(), + fee: min_fee_to_dest, + origin: origin_location, + dest: dest_location, + recipient, + weight: max_weight.unwrap_or(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), + 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, 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 super::*; + use crate::mock::para::{ + assert_events, Assets, NativeAssetId, PBALocation, Runtime, RuntimeEvent, + RuntimeOrigin, UsdtAssetId, UsdtLocation, + }; + use crate::mock::{ + ParaA, ParaAssets, ParaB, ParaBalances, ParaC, TestNet, ALICE, ASSET_OWNER, BOB, + ENDOWED_BALANCE, + }; + use crate::Event as SygmaXcmBridgeEvent; + + 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); + + // transfer parachain A native asset from Alice to parachain B on Bob + assert_ok!(BridgeImpl::::transfer( + ALICE.into(), + (Concrete(MultiLocation::new(0, Here)), Fungible(amount)).into(), + MultiLocation::new( + 1, + X2( + Parachain(2u32), + Junction::AccountId32 { network: None, id: BOB.into() }, + ), + ), + None + )); + + // 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(amount)).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() }, + ), + )), + }, + )]); + + // 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(|| { + // 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(); + + // sending 10 tokens + let amount = 10_000_000_000_000u128; + let fee = 4u128; + + // 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(amount)).into(), + MultiLocation::new( + 1, + X2( + 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); + }); + + // 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() } + ) + ), + None + )); + + // 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(PBALocation::get()), Fungible(amount - fee)).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(|| { + // 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)), amount - (amount - fee)); + }); + } + + #[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); + }); + + // 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( + ASSET_OWNER.into(), + (Concrete(UsdtLocation::get()), Fungible(100_000_000u128)).into(), + MultiLocation::new( + 1, + X2( + Parachain(1u32), + Junction::AccountId32 { network: None, id: ALICE.into() }, + ), + ), + None + )); + 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!( + ParaAssets::balance(UsdtAssetId::get(), &ALICE), + 100_000_000u128 - 4u128 + ); + }); + + // 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(100_000_000u128 - 4u128)).into(), + MultiLocation::new( + 1, + X2( + Parachain(2u32), + Junction::AccountId32 { network: None, id: BOB.into() }, + ), + ), + None + )); + // 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(100_000_000u128 - 4u128)) + .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() }, + ), + )), + }, + )]); + }); + + 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(|| { + // 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 new file mode 100644 index 00000000..510d435e --- /dev/null +++ b/xcm-bridge/src/mock/mod.rs @@ -0,0 +1,111 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +#![cfg(test)] + +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 para; +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; +pub type ParaAssets = pallet_assets::Pallet; + +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::Runtime, + XcmpMessageHandler = para::XcmpQueue, + DmpMessageHandler = para::DmpQueue, + new_ext = para_ext(2005), // for USDT + } +} + +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), + (2005, 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(); + + // 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), + (ASSET_OWNER, 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 +} diff --git a/xcm-bridge/src/mock/para.rs b/xcm-bridge/src/mock/para.rs new file mode 100644 index 00000000..7c470d9b --- /dev/null +++ b/xcm-bridge/src/mock/para.rs @@ -0,0 +1,381 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +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, + traits::{AsEnsureOriginWithArg, ConstU128, ConstU32, Everything}, +}; +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 sygma_traits::AssetTypeIdentifier; +use xcm::latest::{ + AssetId as XcmAssetId, InteriorMultiLocation, MultiAsset, MultiLocation, NetworkId, + Weight as XCMWeight, XcmContext, +}; +use xcm::prelude::{Concrete, Fungible, GlobalConsensus, Parachain, XcmError, X1, X2}; +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 crate as sygma_xcm_bridge; +use crate::BridgeImpl; + +use super::ParachainXcmRouter; + +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}, + + 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}, + } +); + +type Block = frame_system::mocking::MockBlock; + +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; + 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 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 sygma_xcm_bridge::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Weigher = FixedWeightBounds; + type XcmExecutor = XcmExecutor; + type AssetReservedChecker = NativeAssetTypeIdentifier; + 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; +} + +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 = 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, +); + +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 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, + X1( + Parachain(2005), + ), + ); + // Parachain A and Parachain B native asset multilocation + 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())); + + // 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<()>); +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 if id == &PBALocation::get() || id == &PAALocation::get() { + Ok((NativeAssetId::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, +>; + +/// 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 { + 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 = (); +} + +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; +} + +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, 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(); + + expected.reverse(); + + for evt in expected { + let next = actual.pop().expect("event expected"); + assert_eq!(next, evt, "Events don't match"); + } +} diff --git a/xcm-bridge/src/mock/relay.rs b/xcm-bridge/src/mock/relay.rs new file mode 100644 index 00000000..745dc5c1 --- /dev/null +++ b/xcm-bridge/src/mock/relay.rs @@ -0,0 +1,235 @@ +// The Licensed Work is (c) 2022 Sygma +// SPDX-License-Identifier: LGPL-3.0-only + +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}, +}; +use frame_system::EnsureRoot; +use polkadot_runtime_parachains::{ + configuration, + inclusion::{AggregateMessageOrigin, UmpQueueId}, + origin, shared, +}; +use sp_core::H256; +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, +}; +use xcm_executor::{traits::WithOriginFilter, Config, 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; + +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) = (Rococo::get(), Statemine::get()); +} + +parameter_types! { + pub const UnitWeightCost: Weight = Weight::from_parts(10, 10); + 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; + 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 = (); +}