diff --git a/Cargo.lock b/Cargo.lock index 0ffd6692e0..8acf047fba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,7 +68,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.5", + "getrandom 0.2.4", "once_cell", "version_check", ] @@ -99,9 +99,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" [[package]] name = "approx" @@ -188,9 +188,9 @@ dependencies = [ [[package]] name = "async-global-executor" -version = "2.0.3" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026b7e44f1316b567ee750fea85103f87fcb80792b860e979f221259796ca0a" +checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" dependencies = [ "async-channel", "async-executor", @@ -301,9 +301,9 @@ dependencies = [ [[package]] name = "async-task" -version = "4.2.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" +checksum = "677d306121baf53310a3fd342d88dc0824f6bbeace68347593658525565abee8" [[package]] name = "async-trait" @@ -487,6 +487,26 @@ dependencies = [ "sp-std", ] +[[package]] +name = "bifrost-asset-registry" +version = "0.8.0" +dependencies = [ + "frame-support", + "frame-system", + "log", + "node-primitives", + "pallet-balances", + "parity-scale-codec 2.3.1", + "scale-info 1.0.0", + "serde", + "sp-io", + "sp-runtime", + "sp-std", + "xcm", + "xcm-builder", + "xcm-executor", +] + [[package]] name = "bifrost-call-switchgear" version = "0.8.0" @@ -569,6 +589,7 @@ dependencies = [ name = "bifrost-kusama-runtime" version = "0.8.0" dependencies = [ + "bifrost-asset-registry", "bifrost-call-switchgear", "bifrost-flexible-fee", "bifrost-flexible-fee-rpc-runtime-api", @@ -1148,9 +1169,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blocking" -version = "1.2.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" +checksum = "046e47d4b2d391b1f6f8b407b1deb8dee56c1852ccd868becf2710f601b5f427" dependencies = [ "async-channel", "async-task", @@ -1357,9 +1378,9 @@ checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "byte-slice-cast" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e" +checksum = "1d30c751592b77c499e7bce34d99d67c2c11bdc0574e9a488ddade14150a4698" [[package]] name = "byte-tools" @@ -2489,9 +2510,9 @@ checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" [[package]] name = "ed25519" -version = "1.4.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed12bbf7b5312f8da1c2722bc06d8c6b12c2d86a7fb35a194c7f3e6fc2bbe39" +checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816" dependencies = [ "signature", ] @@ -2518,11 +2539,11 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "enum-as-inner" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "570d109b813e904becc80d8d5da38376818a143348413f7149f1340fe04754d4" +checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" dependencies = [ - "heck 0.4.0", + "heck 0.3.3", "proc-macro2", "quote", "syn", @@ -3144,9 +3165,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if 1.0.0", "libc", @@ -3207,9 +3228,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.12" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b" +checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" dependencies = [ "bytes 1.1.0", "fnv", @@ -3226,9 +3247,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "4.2.2" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d6a30320f094710245150395bc763ad23128d6a1ebbad7594dc4164b62c56b" +checksum = "25546a65e5cf1f471f3438796fc634650b31d7fcde01d444c309aeb28b92e3a8" dependencies = [ "log", "pest", @@ -3546,9 +3567,9 @@ dependencies = [ [[package]] name = "integer-encoding" -version = "3.0.3" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e85a1509a128c855368e135cffcde7eac17d8e1083f41e2b98c58bc1a5074be" +checksum = "90c11140ffea82edce8dcd74137ce9324ec24b3cf0175fc9d7e29164da9915b8" [[package]] name = "integer-sqrt" @@ -3597,9 +3618,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.4.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] name = "itertools" @@ -4504,7 +4525,7 @@ dependencies = [ "libp2p-core", "libp2p-swarm", "log", - "lru 0.7.3", + "lru 0.7.2", "rand 0.7.3", "smallvec", "unsigned-varint 0.7.1", @@ -4673,9 +4694,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.5" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859" +checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" dependencies = [ "cc", "pkg-config", @@ -4752,9 +4773,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.7.3" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb87f3080f6d1d69e8c564c0fcfde1d7aa8cc451ce40cae89479111f03bc0eb" +checksum = "274353858935c992b13c0ca408752e2121da852d07dec7ce5f108c77dfa14d1f" dependencies = [ "hashbrown 0.11.2", ] @@ -4770,9 +4791,9 @@ dependencies = [ [[package]] name = "lz4" -version = "1.23.3" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4edcb94251b1c375c459e5abe9fb0168c1c826c3370172684844f8f3f8d1a885" +checksum = "aac20ed6991e01bf6a2e68cc73df2b389707403662a8ba89f68511fb340f724c" dependencies = [ "libc", "lz4-sys", @@ -4780,9 +4801,9 @@ dependencies = [ [[package]] name = "lz4-sys" -version = "1.9.3" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7be8908e2ed6f31c02db8a9fa962f03e36c53fbfde437363eae3306b85d7e17" +checksum = "dca79aa95d8b3226213ad454d328369853be3a1382d89532a854f4d69640acae" dependencies = [ "cc", "libc", @@ -4938,9 +4959,9 @@ dependencies = [ [[package]] name = "mick-jaeger" -version = "0.1.8" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69672161530e8aeca1d1400fbf3f1a1747ff60ea604265a4e906c2442df20532" +checksum = "fd2c2cc134e57461f0898b0e921f0a7819b5e3f3a4335b9aa390ce81a5f36fb9" dependencies = [ "futures 0.3.21", "rand 0.8.5", @@ -4984,15 +5005,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8" +checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" dependencies = [ "libc", "log", "miow 0.3.7", "ntapi", - "wasi 0.11.0+wasi-snapshot-preview1", "winapi 0.3.9", ] @@ -5456,9 +5476,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] name = "opaque-debug" @@ -6645,9 +6665,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.8" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "865edee5b792f537356d9e55cbc138e7f4718dc881a7ea45a18b37bf61c21e3d" +checksum = "09aa6c5bb8070cf0456d9fc228b3022e900aae9092c48c9c45facf97422efc1d" dependencies = [ "blake2-rfc", "crc32fast", @@ -6678,14 +6698,14 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.1.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8483b84fb12de1dc23bf95d26030d16cea56391d136db0db37f749508104e3e6" +checksum = "e8b44461635bbb1a0300f100a841e571e7d919c81c73075ef5d152ffdb521066" dependencies = [ "arrayvec 0.7.2", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive 3.1.0", + "parity-scale-codec-derive 3.1.2", ] [[package]] @@ -6702,9 +6722,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7259388ceb4c23bc09caef272c9e7a732b3b8f9fbd0b41f0009a91d6548cc1d9" +checksum = "c45ed1f39709f5a89338fab50e59816b2e8815f5bb58276e7ddf9afd495f73f8" dependencies = [ "proc-macro-crate 1.1.3", "proc-macro2", @@ -6852,7 +6872,7 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall 0.2.11", + "redox_syscall 0.2.10", "smallvec", "winapi 0.3.9", ] @@ -6865,7 +6885,7 @@ checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.2.11", + "redox_syscall 0.2.10", "smallvec", "windows-sys", ] @@ -7069,7 +7089,7 @@ source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.17#de0e dependencies = [ "derive_more", "futures 0.3.21", - "lru 0.7.3", + "lru 0.7.2", "parity-scale-codec 2.3.1", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -7090,7 +7110,7 @@ version = "0.9.17" source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.17#de0ecd4760b146ecf33f5e867d707d789e21e060" dependencies = [ "futures 0.3.21", - "lru 0.7.3", + "lru 0.7.2", "parity-scale-codec 2.3.1", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -7198,7 +7218,7 @@ source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.17#de0e dependencies = [ "derive_more", "futures 0.3.21", - "lru 0.7.3", + "lru 0.7.2", "parity-scale-codec 2.3.1", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -7294,7 +7314,7 @@ dependencies = [ "futures 0.3.21", "futures-timer", "kvdb", - "lru 0.7.3", + "lru 0.7.2", "merlin", "parity-scale-codec 2.3.1", "polkadot-node-jaeger", @@ -7422,7 +7442,7 @@ source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.17#de0e dependencies = [ "futures 0.3.21", "kvdb", - "lru 0.7.3", + "lru 0.7.2", "parity-scale-codec 2.3.1", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -7646,7 +7666,7 @@ dependencies = [ "derive_more", "futures 0.3.21", "itertools", - "lru 0.7.3", + "lru 0.7.2", "metered-channel", "parity-scale-codec 2.3.1", "pin-project 1.0.10", @@ -7672,7 +7692,7 @@ source = "git+https://github.com/paritytech/polkadot?branch=release-v0.9.17#de0e dependencies = [ "futures 0.3.21", "futures-timer", - "lru 0.7.3", + "lru 0.7.2", "parity-util-mem", "parking_lot 0.11.2", "polkadot-node-metrics", @@ -8018,7 +8038,7 @@ dependencies = [ "kusama-runtime", "kvdb", "kvdb-rocksdb", - "lru 0.7.3", + "lru 0.7.2", "pallet-babe", "pallet-im-online", "pallet-mmr-primitives", @@ -8416,7 +8436,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.5", + "getrandom 0.2.4", ] [[package]] @@ -8486,9 +8506,9 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_syscall" -version = "0.2.11" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -8499,8 +8519,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.2.5", - "redox_syscall 0.2.11", + "getrandom 0.2.4", + "redox_syscall 0.2.10", ] [[package]] @@ -8549,9 +8569,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -8623,9 +8643,9 @@ dependencies = [ [[package]] name = "retain_mut" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c31b5c4033f8fdde8700e4657be2c497e7288f01515be52168c631e2e4d4086" +checksum = "51dd4445360338dab5116712bee1388dc727991d51969558a8882ab552e6db30" [[package]] name = "ring" @@ -9590,7 +9610,7 @@ dependencies = [ "linked-hash-map", "linked_hash_set", "log", - "lru 0.7.3", + "lru 0.7.2", "parity-scale-codec 2.3.1", "parking_lot 0.11.2", "pin-project 1.0.10", @@ -9627,7 +9647,7 @@ dependencies = [ "futures-timer", "libp2p", "log", - "lru 0.7.3", + "lru 0.7.2", "sc-network", "sp-runtime", "substrate-prometheus-endpoint", @@ -9991,7 +10011,7 @@ checksum = "0563970d79bcbf3c537ce3ad36d859b30d36fc5b190efd227f1f7a84d7cf0d42" dependencies = [ "cfg-if 1.0.0", "derive_more", - "parity-scale-codec 3.1.0", + "parity-scale-codec 3.1.2", "scale-info-derive 2.0.0", ] @@ -10504,7 +10524,7 @@ source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.17#22 dependencies = [ "futures 0.3.21", "log", - "lru 0.7.3", + "lru 0.7.2", "parity-scale-codec 2.3.1", "parking_lot 0.11.2", "sp-api", @@ -11222,7 +11242,7 @@ name = "substrate-fixed" version = "0.5.9" source = "git+https://github.com/encointer/substrate-fixed#a4fb461aae6205ffc55bed51254a40c52be04e5d" dependencies = [ - "parity-scale-codec 3.1.0", + "parity-scale-codec 3.1.2", "scale-info 2.0.1", "typenum 1.16.0", ] @@ -11329,16 +11349,16 @@ dependencies = [ "cfg-if 1.0.0", "fastrand", "libc", - "redox_syscall 0.2.11", + "redox_syscall 0.2.10", "remove_dir_all", "winapi 0.3.9", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ "winapi-util", ] @@ -11463,7 +11483,7 @@ dependencies = [ "bytes 1.1.0", "libc", "memchr", - "mio 0.8.1", + "mio 0.8.0", "num_cpus", "once_cell", "pin-project-lite 0.2.8", @@ -11549,9 +11569,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.32" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" dependencies = [ "cfg-if 1.0.0", "pin-project-lite 0.2.8", @@ -11561,9 +11581,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.20" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" dependencies = [ "proc-macro2", "quote", @@ -11572,9 +11592,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.23" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" dependencies = [ "lazy_static", "valuable", @@ -11758,7 +11778,7 @@ name = "typenum" version = "1.16.0" source = "git+https://github.com/encointer/typenum?tag=v1.16.0#4c8dddaa8bdd13130149e43b4085ad14e960617f" dependencies = [ - "parity-scale-codec 3.1.0", + "parity-scale-codec 3.1.2", "scale-info 2.0.1", ] @@ -11958,12 +11978,6 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - [[package]] name = "wasm-bindgen" version = "0.2.79" @@ -12779,9 +12793,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.3" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50344758e2f40e3a1fcfc8f6f91aa57b5f8ebd8d27919fe6451f15aaaf9ee608" +checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006" dependencies = [ "zeroize_derive", ] diff --git a/Cargo.toml b/Cargo.toml index 42d001da63..44239cf225 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "node/primitives", "node/rpc", "node/service", + "pallets/asset-registry", "pallets/flexible-fee", "pallets/lightening-redeem", "pallets/liquidity-mining", diff --git a/Makefile b/Makefile index 740ce31c1f..66c4bfc748 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ build-bifrost-polkadot-wasm: .PHONY: build-bifrost-rococo-fast-wasm build-bifrost-rococo-fast-wasm: - .maintain/build-wasm.sh bifrost-kusama fast + .maintain/build-wasm.sh bifrost-kusama fast .PHONY: check-try-runtime check-try-runtime: @@ -124,7 +124,7 @@ insert-session-key: .PHONY: generate-node-key generate-node-key: - subkey generate-node-key --file ./resources/node-key + subkey generate-node-key --file ./resources/node-key .PHONY: view-key view-key: diff --git a/README.md b/README.md index c759c11e13..6c57034b80 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ cd - ```bash git clone -n https://github.com/paritytech/polkadot.git /tmp/polkadot cd /tmp/polkadot -git checkout release-v0.9.16 +git checkout release-v0.9.17 cargo build --release cd - ``` diff --git a/integration-tests/src/integration_tests.rs b/integration-tests/src/integration_tests.rs index 4ba90d9821..e2517058aa 100644 --- a/integration-tests/src/integration_tests.rs +++ b/integration-tests/src/integration_tests.rs @@ -181,6 +181,8 @@ fn parachain_subaccounts_are_unique() { hex_literal::hex!["70617261d1070000000000000000000000000000000000000000000000000000"] .into() ); + + assert_eq!(RelaychainSovereignSubAccount::get(), create_x2_multilocation(0)); }); } diff --git a/integration-tests/src/statemine.rs b/integration-tests/src/statemine.rs index 560d8144a3..62d0d0355e 100644 --- a/integration-tests/src/statemine.rs +++ b/integration-tests/src/statemine.rs @@ -25,6 +25,7 @@ use xcm_emulator::TestExt; use crate::{integration_tests::*, kusama_test_net::*}; #[test] fn statemine() { + env_logger::init(); Statemine::execute_with(|| { use frame_support::traits::Currency; use westmint_runtime::*; diff --git a/node/primitives/src/currency.rs b/node/primitives/src/currency.rs index f62e46c28f..0a920bd80e 100644 --- a/node/primitives/src/currency.rs +++ b/node/primitives/src/currency.rs @@ -156,6 +156,7 @@ macro_rules! create_currency_id { | Self::Stable(ts) | Self::VSToken(ts) | Self::VSBond(ts, ..) => ts as u8, + Self::ForeignAsset(..) => 0u8, Self::LPToken(..) => 0u8 } as u64; @@ -188,52 +189,56 @@ macro_rules! create_currency_id { Self::LPToken(token_symbol_1, token_type_1, token_symbol_2, token_type_2) => { (((*token_symbol_1 as u64) << 16) & 0x0000_0000_00ff_0000) + (((*token_type_1 as u64) << 24) & 0x0000_0000_ff00_0000) + (((*token_symbol_2 as u64) << 32) & 0x0000_00ff_0000_0000) + (((*token_type_2 as u64) << 40) & 0x0000_ff00_0000_0000) + discr + }, + Self::ForeignAsset(asset_token_id) => { + (((*asset_token_id as u64) << 16) & 0x0000_ffff_ffff_0000) + discr } } } - fn name(&self) -> &str { + fn name(&self) -> Option<&str> { match self { - $(CurrencyId::Native(TokenSymbol::$symbol) => $name,)* - $(CurrencyId::Stable(TokenSymbol::$symbol) => $name,)* - $(CurrencyId::Token(TokenSymbol::$symbol) => $name,)* - $(CurrencyId::VToken(TokenSymbol::$symbol) => $name,)* - $(CurrencyId::VSToken(TokenSymbol::$symbol) => $name,)* - $(CurrencyId::VSBond(TokenSymbol::$symbol, ..) => $name,)* + $(CurrencyId::Native(TokenSymbol::$symbol) => Some($name),)* + $(CurrencyId::Stable(TokenSymbol::$symbol) => Some($name),)* + $(CurrencyId::Token(TokenSymbol::$symbol) => Some($name),)* + $(CurrencyId::VToken(TokenSymbol::$symbol) => Some($name),)* + $(CurrencyId::VSToken(TokenSymbol::$symbol) => Some($name),)* + $(CurrencyId::VSBond(TokenSymbol::$symbol, ..) => Some($name),)* CurrencyId::LPToken(ts1, type1, ts2, type2) => { let c1_u64: u64 = (((*type1 as u64) << 8) & 0x0000_0000_0000_ff00) + ((*ts1 as u64) & 0x0000_0000_0000_00ff); let c2_u64: u64 = (((*type2 as u64) << 8) & 0x0000_0000_0000_ff00) + ((*ts2 as u64) & 0x0000_0000_0000_00ff); let _c1: CurrencyId = c1_u64.try_into().unwrap_or_default(); let _c2: CurrencyId = c2_u64.try_into().unwrap_or_default(); - stringify!(_c1.name(), ",", _c2.name()) - } + Some(stringify!(_c1.name(), ",", _c2.name())) + }, + _ => None } } - fn symbol(&self) -> &str { + fn symbol(&self) -> Option<&str> { match self { - $(CurrencyId::Native(TokenSymbol::$symbol) => stringify!($symbol),)* - $(CurrencyId::Stable(TokenSymbol::$symbol) => stringify!($symbol),)* - $(CurrencyId::Token(TokenSymbol::$symbol) => stringify!($symbol),)* - $(CurrencyId::VToken(TokenSymbol::$symbol) => stringify!($symbol),)* - $(CurrencyId::VSToken(TokenSymbol::$symbol) => stringify!($symbol),)* - $(CurrencyId::VSBond(TokenSymbol::$symbol, ..) => stringify!($symbol),)* - CurrencyId::LPToken(_ts1, _, _ts2, _) => { - stringify!(_ts1, ",", _ts2) - } + $(CurrencyId::Native(TokenSymbol::$symbol) => Some(stringify!($symbol)),)* + $(CurrencyId::Stable(TokenSymbol::$symbol) => Some(stringify!($symbol)),)* + $(CurrencyId::Token(TokenSymbol::$symbol) => Some(stringify!($symbol)),)* + $(CurrencyId::VToken(TokenSymbol::$symbol) => Some(stringify!($symbol)),)* + $(CurrencyId::VSToken(TokenSymbol::$symbol) => Some(stringify!($symbol)),)* + $(CurrencyId::VSBond(TokenSymbol::$symbol, ..) => Some(stringify!($symbol)),)* + CurrencyId::LPToken(_ts1, _, _ts2, _) => Some(stringify!(_ts1, ",", _ts2)), + _ => None } } - fn decimals(&self) -> u8 { + fn decimals(&self) -> Option { match self { - $(CurrencyId::Native(TokenSymbol::$symbol) => $deci,)* - $(CurrencyId::Stable(TokenSymbol::$symbol) => $deci,)* - $(CurrencyId::Token(TokenSymbol::$symbol) => $deci,)* - $(CurrencyId::VToken(TokenSymbol::$symbol) => $deci,)* - $(CurrencyId::VSToken(TokenSymbol::$symbol) => $deci,)* - $(CurrencyId::VSBond(TokenSymbol::$symbol, ..) => $deci,)* - CurrencyId::LPToken(..) => 1u8 + $(CurrencyId::Native(TokenSymbol::$symbol) => Some($deci),)* + $(CurrencyId::Stable(TokenSymbol::$symbol) => Some($deci),)* + $(CurrencyId::Token(TokenSymbol::$symbol) => Some($deci),)* + $(CurrencyId::VToken(TokenSymbol::$symbol) => Some($deci),)* + $(CurrencyId::VSToken(TokenSymbol::$symbol) => Some($deci),)* + $(CurrencyId::VSBond(TokenSymbol::$symbol, ..) => Some($deci),)* + CurrencyId::LPToken(..) => Some(1u8), + _ => None } } } @@ -280,6 +285,8 @@ impl Default for TokenSymbol { } } +pub type ForeignAssetId = u32; + /// Currency ID, it might be extended with more variants in the future. #[derive( Encode, @@ -305,6 +312,7 @@ pub enum CurrencyId { VSBond(TokenSymbol, ParaId, LeasePeriod, LeasePeriod), // [currency1 Tokensymbol, currency1 TokenType, currency2 TokenSymbol, currency2 TokenType] LPToken(TokenSymbol, u8, TokenSymbol, u8), + ForeignAsset(ForeignAssetId), } impl Default for CurrencyId { @@ -368,6 +376,7 @@ impl CurrencyId { Self::VSToken(..) => 4, Self::VSBond(..) => 5, Self::LPToken(..) => 6, + Self::ForeignAsset(..) => 7, } } } @@ -403,6 +412,10 @@ impl CurrencyIdExt for CurrencyId { matches!(self, CurrencyId::LPToken(..)) } + fn is_foreign_asset(&self) -> bool { + matches!(self, CurrencyId::ForeignAsset(..)) + } + fn into(symbol: Self::TokenSymbol) -> Self { CurrencyId::Token(symbol) } @@ -440,6 +453,10 @@ impl TryFrom for CurrencyId { Ok(Self::LPToken(token_symbol_1, token_type_1, token_symbol_2, token_type_2)) }, + 7 => { + let foreign_asset_id = ((id & 0x0000_ffff_ffff_0000) >> 16) as ForeignAssetId; + Ok(Self::ForeignAsset(foreign_asset_id)) + }, _ => Err(()), } } diff --git a/node/primitives/src/lib.rs b/node/primitives/src/lib.rs index 58312fbfe4..532afe4245 100644 --- a/node/primitives/src/lib.rs +++ b/node/primitives/src/lib.rs @@ -38,7 +38,7 @@ mod tests; pub use crate::{ bridge::*, - currency::{CurrencyId, TokenSymbol}, + currency::{CurrencyId, ForeignAssetId, TokenSymbol}, traits::*, }; diff --git a/node/primitives/src/tests.rs b/node/primitives/src/tests.rs index a678c27373..86a6e53f79 100644 --- a/node/primitives/src/tests.rs +++ b/node/primitives/src/tests.rs @@ -135,6 +135,18 @@ fn currency_id_to_u64_should_work() { assert_eq!(0x0000_0103_0002_0600, e61.currency_id()); assert_eq!(0x0000_0205_0104_0600, e62.currency_id()); assert_eq!(0x0000_0406_0300_0600, e63.currency_id()); + + let e70 = CurrencyId::ForeignAsset(0); + let e71 = CurrencyId::ForeignAsset(1); + let e72 = CurrencyId::ForeignAsset(255); + let e73 = CurrencyId::ForeignAsset(256); + let e74 = CurrencyId::ForeignAsset(ForeignAssetId::MAX); + + assert_eq!(0x0000_0000_0000_0700, e70.currency_id()); + assert_eq!(0x0000_0000_0001_0700, e71.currency_id()); + assert_eq!(0x0000_0000_00ff_0700, e72.currency_id()); + assert_eq!(0x0000_0000_0100_0700, e73.currency_id()); + assert_eq!(0x0000_ffff_ffff_0700, e74.currency_id()); } #[test] @@ -245,4 +257,16 @@ fn u64_to_currency_id_should_work() { assert_eq!(e61, CurrencyId::try_from(0x0000_0103_0002_0600).unwrap()); assert_eq!(e62, CurrencyId::try_from(0x0000_0205_0104_0600).unwrap()); assert_eq!(e63, CurrencyId::try_from(0x0000_0406_0300_0600).unwrap()); + + let e70 = CurrencyId::ForeignAsset(0); + let e71 = CurrencyId::ForeignAsset(1); + let e72 = CurrencyId::ForeignAsset(255); + let e73 = CurrencyId::ForeignAsset(256); + let e74 = CurrencyId::ForeignAsset(ForeignAssetId::MAX); + + assert_eq!(e70, CurrencyId::try_from(0x0000_0000_0000_0700).unwrap()); + assert_eq!(e71, CurrencyId::try_from(0x0000_0000_0001_0700).unwrap()); + assert_eq!(e72, CurrencyId::try_from(0x0000_0000_00ff_0700).unwrap()); + assert_eq!(e73, CurrencyId::try_from(0x0000_0000_0100_0700).unwrap()); + assert_eq!(e74, CurrencyId::try_from(0x0000_ffff_ffff_0700).unwrap()); } diff --git a/node/primitives/src/traits.rs b/node/primitives/src/traits.rs index 3511ae9386..af929fd40a 100644 --- a/node/primitives/src/traits.rs +++ b/node/primitives/src/traits.rs @@ -31,13 +31,13 @@ use sp_runtime::{ }; use sp_std::{fmt::Debug, vec::Vec}; -use crate::BridgeAssetBalance; +use crate::{BridgeAssetBalance, CurrencyId}; pub trait TokenInfo { fn currency_id(&self) -> u64; - fn name(&self) -> &str; - fn symbol(&self) -> &str; - fn decimals(&self) -> u8; + fn name(&self) -> Option<&str>; + fn symbol(&self) -> Option<&str>; + fn decimals(&self) -> Option; } /// Extension trait for CurrencyId @@ -50,6 +50,7 @@ pub trait CurrencyIdExt { fn is_native(&self) -> bool; fn is_stable(&self) -> bool; fn is_lptoken(&self) -> bool; + fn is_foreign_asset(&self) -> bool; fn into(symbol: Self::TokenSymbol) -> Self; } @@ -195,3 +196,13 @@ where } } } + +/// A mapping between AssetId and AssetMetadata. +pub trait AssetIdMapping { + /// Returns the AssetMetadata associated with a given ForeignAssetId. + fn get_foreign_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option; + /// Returns the MultiLocation associated with a given ForeignAssetId. + fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option; + /// Returns the CurrencyId associated with a given MultiLocation. + fn get_currency_id(multi_location: MultiLocation) -> Option; +} diff --git a/node/service/src/chain_spec/bifrost_kusama.rs b/node/service/src/chain_spec/bifrost_kusama.rs index 80df9cf2e5..f72a4d214c 100644 --- a/node/service/src/chain_spec/bifrost_kusama.rs +++ b/node/service/src/chain_spec/bifrost_kusama.rs @@ -105,8 +105,8 @@ fn bifrost_kusama_properties() -> Properties { ] .iter() .for_each(|token| { - token_symbol.push(token.symbol().to_string()); - token_decimals.push(token.decimals() as u32); + token_symbol.push(token.symbol().expect("Token symbol expected").to_string()); + token_decimals.push(token.decimals().expect("Token decimals expected") as u32); }); properties.insert("tokenSymbol".into(), token_symbol.into()); diff --git a/node/service/src/chain_spec/bifrost_polkadot.rs b/node/service/src/chain_spec/bifrost_polkadot.rs index a3c59dc18f..b7194de3c9 100644 --- a/node/service/src/chain_spec/bifrost_polkadot.rs +++ b/node/service/src/chain_spec/bifrost_polkadot.rs @@ -57,8 +57,8 @@ fn bifrost_polkadot_properties() -> Properties { ] .iter() .for_each(|token| { - token_symbol.push(token.symbol().to_string()); - token_decimals.push(token.decimals() as u32); + token_symbol.push(token.symbol().expect("Token symbol expected").to_string()); + token_decimals.push(token.decimals().expect("Token decimals expected") as u32); }); properties.insert("tokenSymbol".into(), token_symbol.into()); diff --git a/pallets/asset-registry/Cargo.toml b/pallets/asset-registry/Cargo.toml new file mode 100644 index 0000000000..8e5c374702 --- /dev/null +++ b/pallets/asset-registry/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "bifrost-asset-registry" +version = "0.8.0" +authors = ["Edwin Wang "] +edition = "2021" + +[dependencies] +log = { version = "0.4.14", default-features = false } +serde = { version = "1.0.124", optional = true } +scale-info = { version = "1.0", default-features = false, features = ["derive"] } +codec = { package = "parity-scale-codec", version = "2.3.1", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.17", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.17", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.17", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.17", default-features = false } +primitives = { package = "node-primitives", path = "../../node/primitives", default-features = false } + +xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.17", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.17", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.17", default-features = false } + +[dev-dependencies] +sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.17" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.17" } + +[features] +default = ["std"] +std = [ + "serde", + "log/std", + "codec/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", + "frame-support/std", + "frame-system/std", + "primitives/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/asset-registry/src/lib.rs b/pallets/asset-registry/src/lib.rs new file mode 100644 index 0000000000..bb062bcfa7 --- /dev/null +++ b/pallets/asset-registry/src/lib.rs @@ -0,0 +1,428 @@ +// This file is part of Bifrost. + +// Copyright (C) 2019-2022 Liebi Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! # Asset Registry Module +//! +//! Local and foreign assets management. The foreign assets can be updated without runtime upgrade. + +#![cfg_attr(not(feature = "std"), no_std)] +#![allow(clippy::unused_unit)] + +use frame_support::{ + dispatch::DispatchResult, + ensure, + pallet_prelude::*, + traits::{Currency, EnsureOrigin}, + transactional, + weights::constants::WEIGHT_PER_SECOND, + RuntimeDebug, +}; +use frame_system::pallet_prelude::*; +use primitives::{AssetIdMapping, CurrencyId, ForeignAssetId}; +use scale_info::TypeInfo; +use sp_runtime::{traits::One, ArithmeticError, FixedPointNumber, FixedU128}; +use sp_std::{boxed::Box, vec::Vec}; +// NOTE:v1::MultiLocation is used in storages, we would need to do migration if upgrade the +// MultiLocation in the future. +use xcm::{ + opaque::latest::{prelude::XcmError, AssetId, Fungibility::Fungible, MultiAsset}, + v1::MultiLocation, + VersionedMultiLocation, +}; +use xcm_builder::TakeRevenue; +use xcm_executor::{traits::WeightTrader, Assets}; + +mod mock; +mod tests; + +pub use pallet::*; + +/// Type alias for currency balance. +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type Event: From> + IsType<::Event>; + + /// Currency type for withdraw and balance storage. + type Currency: Currency; + + /// Required origin for registering asset. + type RegisterOrigin: EnsureOrigin; + } + + #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)] + pub enum AssetIds { + ForeignAssetId(ForeignAssetId), + } + + #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)] + pub struct AssetMetadata { + pub name: Vec, + pub symbol: Vec, + pub decimals: u8, + pub minimal_balance: Balance, + } + + #[pallet::error] + pub enum Error { + /// The given location could not be used (e.g. because it cannot be expressed in the + /// desired version of XCM). + BadLocation, + /// MultiLocation existed + MultiLocationExisted, + /// AssetId not exists + AssetIdNotExists, + /// AssetId exists + AssetIdExisted, + } + + #[pallet::event] + #[pallet::generate_deposit(fn deposit_event)] + pub enum Event { + /// The foreign asset registered. + ForeignAssetRegistered { + asset_id: ForeignAssetId, + asset_address: MultiLocation, + metadata: AssetMetadata>, + }, + /// The foreign asset updated. + ForeignAssetUpdated { + asset_id: ForeignAssetId, + asset_address: MultiLocation, + metadata: AssetMetadata>, + }, + /// The asset registered. + AssetRegistered { asset_id: AssetIds, metadata: AssetMetadata> }, + /// The asset updated. + AssetUpdated { asset_id: AssetIds, metadata: AssetMetadata> }, + } + + /// Next available Foreign AssetId ID. + /// + /// NextForeignAssetId: ForeignAssetId + #[pallet::storage] + #[pallet::getter(fn next_foreign_asset_id)] + pub type NextForeignAssetId = StorageValue<_, ForeignAssetId, ValueQuery>; + + /// The storages for MultiLocations. + /// + /// ForeignAssetLocations: map ForeignAssetId => Option + #[pallet::storage] + #[pallet::getter(fn foreign_asset_locations)] + pub type ForeignAssetLocations = + StorageMap<_, Twox64Concat, ForeignAssetId, MultiLocation, OptionQuery>; + + /// The storages for CurrencyIds. + /// + /// LocationToCurrencyIds: map MultiLocation => Option + #[pallet::storage] + #[pallet::getter(fn location_to_currency_ids)] + pub type LocationToCurrencyIds = + StorageMap<_, Twox64Concat, MultiLocation, CurrencyId, OptionQuery>; + + /// The storages for AssetMetadatas. + /// + /// AssetMetadatas: map AssetIds => Option + #[pallet::storage] + #[pallet::getter(fn asset_metadatas)] + pub type AssetMetadatas = + StorageMap<_, Twox64Concat, AssetIds, AssetMetadata>, OptionQuery>; + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(_); + + #[pallet::call] + impl Pallet { + #[pallet::weight(1000000)] + #[transactional] + pub fn register_foreign_asset( + origin: OriginFor, + location: Box, + metadata: Box>>, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + let location: MultiLocation = + (*location).try_into().map_err(|()| Error::::BadLocation)?; + let foreign_asset_id = Self::do_register_foreign_asset(&location, &metadata)?; + + Self::deposit_event(Event::::ForeignAssetRegistered { + asset_id: foreign_asset_id, + asset_address: location, + metadata: *metadata, + }); + Ok(()) + } + + #[pallet::weight(1000000)] + #[transactional] + pub fn update_foreign_asset( + origin: OriginFor, + foreign_asset_id: ForeignAssetId, + location: Box, + metadata: Box>>, + ) -> DispatchResult { + T::RegisterOrigin::ensure_origin(origin)?; + + let location: MultiLocation = + (*location).try_into().map_err(|()| Error::::BadLocation)?; + Self::do_update_foreign_asset(foreign_asset_id, &location, &metadata)?; + + Self::deposit_event(Event::::ForeignAssetUpdated { + asset_id: foreign_asset_id, + asset_address: location, + metadata: *metadata, + }); + Ok(()) + } + } +} + +impl Pallet { + fn get_next_foreign_asset_id() -> Result { + NextForeignAssetId::::try_mutate(|current| -> Result { + let id = *current; + *current = current.checked_add(One::one()).ok_or(ArithmeticError::Overflow)?; + Ok(id) + }) + } + + fn do_register_foreign_asset( + location: &MultiLocation, + metadata: &AssetMetadata>, + ) -> Result { + let foreign_asset_id = Self::get_next_foreign_asset_id()?; + LocationToCurrencyIds::::try_mutate(location, |maybe_currency_ids| -> DispatchResult { + ensure!(maybe_currency_ids.is_none(), Error::::MultiLocationExisted); + *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id)); + + ForeignAssetLocations::::try_mutate( + foreign_asset_id, + |maybe_location| -> DispatchResult { + ensure!(maybe_location.is_none(), Error::::MultiLocationExisted); + *maybe_location = Some(location.clone()); + + AssetMetadatas::::try_mutate( + AssetIds::ForeignAssetId(foreign_asset_id), + |maybe_asset_metadatas| -> DispatchResult { + ensure!(maybe_asset_metadatas.is_none(), Error::::AssetIdExisted); + + *maybe_asset_metadatas = Some(metadata.clone()); + Ok(()) + }, + ) + }, + ) + })?; + + Ok(foreign_asset_id) + } + + fn do_update_foreign_asset( + foreign_asset_id: ForeignAssetId, + location: &MultiLocation, + metadata: &AssetMetadata>, + ) -> DispatchResult { + ForeignAssetLocations::::try_mutate( + foreign_asset_id, + |maybe_multi_locations| -> DispatchResult { + let old_multi_locations = + maybe_multi_locations.as_mut().ok_or(Error::::AssetIdNotExists)?; + + AssetMetadatas::::try_mutate( + AssetIds::ForeignAssetId(foreign_asset_id), + |maybe_asset_metadatas| -> DispatchResult { + ensure!(maybe_asset_metadatas.is_some(), Error::::AssetIdNotExists); + + // modify location + if location != old_multi_locations { + LocationToCurrencyIds::::remove(old_multi_locations.clone()); + LocationToCurrencyIds::::try_mutate( + location, + |maybe_currency_ids| -> DispatchResult { + ensure!( + maybe_currency_ids.is_none(), + Error::::MultiLocationExisted + ); + *maybe_currency_ids = + Some(CurrencyId::ForeignAsset(foreign_asset_id)); + Ok(()) + }, + )?; + } + *maybe_asset_metadatas = Some(metadata.clone()); + *old_multi_locations = location.clone(); + Ok(()) + }, + ) + }, + ) + } +} + +pub struct AssetIdMaps(sp_std::marker::PhantomData); + +impl AssetIdMapping>> + for AssetIdMaps +{ + fn get_foreign_asset_metadata( + foreign_asset_id: ForeignAssetId, + ) -> Option>> { + Pallet::::asset_metadatas(AssetIds::ForeignAssetId(foreign_asset_id)) + } + + fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option { + Pallet::::foreign_asset_locations(foreign_asset_id) + } + + fn get_currency_id(multi_location: MultiLocation) -> Option { + Pallet::::location_to_currency_ids(multi_location) + } +} + +/// Simple fee calculator that requires payment in a single fungible at a fixed rate. +/// +/// The constant `FixedRate` type parameter should be the concrete fungible ID and the amount of it +/// required for one second of weight. +pub struct FixedRateOfForeignAsset, R: TakeRevenue> { + weight: Weight, + amount: u128, + ed_ratio: FixedU128, + multi_location: Option, + _marker: PhantomData<(T, FixedRate, R)>, +} + +impl, R: TakeRevenue> WeightTrader + for FixedRateOfForeignAsset +where + BalanceOf: Into, +{ + fn new() -> Self { + Self { + weight: 0, + amount: 0, + ed_ratio: Default::default(), + multi_location: None, + _marker: PhantomData, + } + } + + fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result { + log::trace!(target: "asset-registry::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment); + + // only support first fungible assets now. + let asset_id = payment + .fungible + .iter() + .next() + .map_or(Err(XcmError::TooExpensive), |v| Ok(v.0))?; + + if let AssetId::Concrete(ref multi_location) = asset_id { + log::debug!(target: "asset-registry::weight", "buy_weight multi_location: {:?}", multi_location); + + if let Some(CurrencyId::ForeignAsset(foreign_asset_id)) = + Pallet::::location_to_currency_ids(multi_location.clone()) + { + if let Some(asset_metadatas) = + Pallet::::asset_metadatas(AssetIds::ForeignAssetId(foreign_asset_id)) + { + // The integration tests can ensure the ed is non-zero. + let ed_ratio = FixedU128::saturating_from_rational( + asset_metadatas.minimal_balance.into(), + T::Currency::minimum_balance().into(), + ); + // The WEIGHT_PER_SECOND is non-zero. + let weight_ratio = FixedU128::saturating_from_rational( + weight as u128, + WEIGHT_PER_SECOND as u128, + ); + let amount = ed_ratio + .saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get())); + + let required = MultiAsset { id: asset_id.clone(), fun: Fungible(amount) }; + + log::trace!( + target: "asset-registry::weight", "buy_weight payment: {:?}, required: {:?}, fixed_rate: {:?}, ed_ratio: {:?}, weight_ratio: {:?}", + payment, required, FixedRate::get(), ed_ratio, weight_ratio + ); + let unused = payment + .clone() + .checked_sub(required) + .map_err(|_| XcmError::TooExpensive)?; + self.weight = self.weight.saturating_add(weight); + self.amount = self.amount.saturating_add(amount); + self.ed_ratio = ed_ratio; + self.multi_location = Some(multi_location.clone()); + return Ok(unused); + } + } + } + + log::trace!(target: "asset-registry::weight", "no concrete fungible asset"); + Err(XcmError::TooExpensive) + } + + fn refund_weight(&mut self, weight: Weight) -> Option { + log::trace!( + target: "asset-registry::weight", "refund_weight weight: {:?}, weight: {:?}, amount: {:?}, ed_ratio: {:?}, multi_location: {:?}", + weight, self.weight, self.amount, self.ed_ratio, self.multi_location + ); + let weight = weight.min(self.weight); + let weight_ratio = + FixedU128::saturating_from_rational(weight as u128, WEIGHT_PER_SECOND as u128); + let amount = self + .ed_ratio + .saturating_mul_int(weight_ratio.saturating_mul_int(FixedRate::get())); + + self.weight = self.weight.saturating_sub(weight); + self.amount = self.amount.saturating_sub(amount); + + log::trace!(target: "asset-registry::weight", "refund_weight amount: {:?}", amount); + if amount > 0 && self.multi_location.is_some() { + Some( + (self.multi_location.as_ref().expect("checked is non-empty; qed").clone(), amount) + .into(), + ) + } else { + None + } + } +} + +impl, R: TakeRevenue> Drop for FixedRateOfForeignAsset { + fn drop(&mut self) { + log::trace!(target: "asset-registry::weight", "take revenue, weight: {:?}, amount: {:?}, multi_location: {:?}", self.weight, self.amount, self.multi_location); + if self.amount > 0 && self.multi_location.is_some() { + R::take_revenue( + ( + self.multi_location.as_ref().expect("checked is non-empty; qed").clone(), + self.amount, + ) + .into(), + ); + } + } +} diff --git a/pallets/asset-registry/src/mock.rs b/pallets/asset-registry/src/mock.rs new file mode 100644 index 0000000000..49fccb92c2 --- /dev/null +++ b/pallets/asset-registry/src/mock.rs @@ -0,0 +1,124 @@ +// This file is part of Bifrost. + +// Copyright (C) 2019-2022 Liebi Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Mocks for asset registry module. + +#![cfg(test)] + +use frame_support::{construct_runtime, ord_parameter_types, parameter_types, traits::Everything}; +use frame_system::EnsureSignedBy; +use primitives::{AccountId, Balance}; + +use crate as asset_registry; + +parameter_types!( + pub const BlockHashCount: u32 = 250; +); + +impl frame_system::Config for Runtime { + type BaseCallFilter = Everything; + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Call = Call; + type Hash = sp_runtime::testing::H256; + type Hashing = sp_runtime::traits::BlakeTwo256; + type AccountId = AccountId; + type Lookup = sp_runtime::traits::IdentityLookup; + type Header = sp_runtime::testing::Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +parameter_types! { + pub const ExistentialDeposit: u64 = 1; + pub const MaxReserves: u32 = 50; +} +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type DustRemoval = (); + type Event = Event; + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = System; + type MaxLocks = (); + type MaxReserves = MaxReserves; + type ReserveIdentifier = [u8; 8]; + type WeightInfo = (); +} + +ord_parameter_types! { + pub const CouncilAccount: AccountId = AccountId::from([1u8; 32]); +} +impl asset_registry::Config for Runtime { + type Event = Event; + type Currency = Balances; + type RegisterOrigin = EnsureSignedBy; +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Event}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + AssetRegistry: asset_registry::{Pallet, Call, Event, Storage}, + } +); + +pub struct ExtBuilder { + balances: Vec<(AccountId, Balance)>, +} + +impl Default for ExtBuilder { + fn default() -> Self { + Self { balances: vec![] } + } +} + +impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: self.balances.into_iter().collect::>(), + } + .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/pallets/asset-registry/src/tests.rs b/pallets/asset-registry/src/tests.rs new file mode 100644 index 0000000000..43165994b3 --- /dev/null +++ b/pallets/asset-registry/src/tests.rs @@ -0,0 +1,327 @@ +// This file is part of Bifrost. + +// Copyright (C) 2019-2022 Liebi Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Unit tests for asset registry module. + +#![cfg(test)] + +use frame_support::{assert_noop, assert_ok}; +use mock::{AssetRegistry, CouncilAccount, Event, ExtBuilder, Origin, Runtime, System}; + +use super::*; + +#[test] +fn versioned_multi_location_convert_work() { + ExtBuilder::default().build().execute_with(|| { + // v0 + let v0_location = VersionedMultiLocation::V0(xcm::v0::MultiLocation::X1( + xcm::v0::Junction::Parachain(1000), + )); + let location: MultiLocation = v0_location.try_into().unwrap(); + assert_eq!( + location, + MultiLocation { + parents: 0, + interior: xcm::v1::Junctions::X1(xcm::v1::Junction::Parachain(1000)) + } + ); + + // v1 + let v1_location = VersionedMultiLocation::V1(MultiLocation { + parents: 0, + interior: xcm::v1::Junctions::X1(xcm::v1::Junction::Parachain(1000)), + }); + let location: MultiLocation = v1_location.try_into().unwrap(); + assert_eq!( + location, + MultiLocation { + parents: 0, + interior: xcm::v1::Junctions::X1(xcm::v1::Junction::Parachain(1000)) + } + ); + + // handle all of VersionedMultiLocation + assert!(match location.into() { + VersionedMultiLocation::V0 { .. } | VersionedMultiLocation::V1 { .. } => true, + }); + }); +} + +#[test] +fn register_foreign_asset_work() { + ExtBuilder::default().build().execute_with(|| { + let v0_location = VersionedMultiLocation::V0(xcm::v0::MultiLocation::X1( + xcm::v0::Junction::Parachain(1000), + )); + + assert_ok!(AssetRegistry::register_foreign_asset( + Origin::signed(CouncilAccount::get()), + Box::new(v0_location.clone()), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + )); + + let location: MultiLocation = v0_location.try_into().unwrap(); + System::assert_last_event(Event::AssetRegistry(crate::Event::ForeignAssetRegistered { + asset_id: 0, + asset_address: location.clone(), + metadata: AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }, + })); + + assert_eq!(ForeignAssetLocations::::get(0), Some(location.clone())); + assert_eq!( + AssetMetadatas::::get(AssetIds::ForeignAssetId(0)), + Some(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + ); + assert_eq!( + LocationToCurrencyIds::::get(location), + Some(CurrencyId::ForeignAsset(0)) + ); + }); +} + +#[test] +fn register_foreign_asset_should_not_work() { + ExtBuilder::default().build().execute_with(|| { + let v0_location = VersionedMultiLocation::V0(xcm::v0::MultiLocation::X1( + xcm::v0::Junction::Parachain(1000), + )); + assert_ok!(AssetRegistry::register_foreign_asset( + Origin::signed(CouncilAccount::get()), + Box::new(v0_location.clone()), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + )); + + assert_noop!( + AssetRegistry::register_foreign_asset( + Origin::signed(CouncilAccount::get()), + Box::new(v0_location), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + ), + Error::::MultiLocationExisted + ); + + NextForeignAssetId::::set(ForeignAssetId::MAX); + assert_noop!( + AssetRegistry::register_foreign_asset( + Origin::signed(CouncilAccount::get()), + Box::new(VersionedMultiLocation::V0(xcm::v0::MultiLocation::X1( + xcm::v0::Junction::Parachain(1000) + ))), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + ), + ArithmeticError::Overflow + ); + }); +} + +#[test] +fn update_foreign_asset_work() { + ExtBuilder::default().build().execute_with(|| { + let v0_location = VersionedMultiLocation::V0(xcm::v0::MultiLocation::X1( + xcm::v0::Junction::Parachain(1000), + )); + + assert_ok!(AssetRegistry::register_foreign_asset( + Origin::signed(CouncilAccount::get()), + Box::new(v0_location.clone()), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + )); + + assert_ok!(AssetRegistry::update_foreign_asset( + Origin::signed(CouncilAccount::get()), + 0, + Box::new(v0_location.clone()), + Box::new(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + )); + + let location: MultiLocation = v0_location.try_into().unwrap(); + System::assert_last_event(Event::AssetRegistry(crate::Event::ForeignAssetUpdated { + asset_id: 0, + asset_address: location.clone(), + metadata: AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }, + })); + + assert_eq!( + AssetMetadatas::::get(AssetIds::ForeignAssetId(0)), + Some(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + ); + assert_eq!(ForeignAssetLocations::::get(0), Some(location.clone())); + assert_eq!( + LocationToCurrencyIds::::get(location.clone()), + Some(CurrencyId::ForeignAsset(0)) + ); + + // modify location + let new_location = VersionedMultiLocation::V0(xcm::v0::MultiLocation::X1( + xcm::v0::Junction::Parachain(2000), + )); + assert_ok!(AssetRegistry::update_foreign_asset( + Origin::signed(CouncilAccount::get()), + 0, + Box::new(new_location.clone()), + Box::new(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + )); + assert_eq!( + AssetMetadatas::::get(AssetIds::ForeignAssetId(0)), + Some(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + ); + let new_location: MultiLocation = new_location.try_into().unwrap(); + assert_eq!(ForeignAssetLocations::::get(0), Some(new_location.clone())); + assert_eq!(LocationToCurrencyIds::::get(location), None); + assert_eq!( + LocationToCurrencyIds::::get(new_location), + Some(CurrencyId::ForeignAsset(0)) + ); + }); +} + +#[test] +fn update_foreign_asset_should_not_work() { + ExtBuilder::default().build().execute_with(|| { + let v0_location = VersionedMultiLocation::V0(xcm::v0::MultiLocation::X1( + xcm::v0::Junction::Parachain(1000), + )); + + assert_noop!( + AssetRegistry::update_foreign_asset( + Origin::signed(CouncilAccount::get()), + 0, + Box::new(v0_location.clone()), + Box::new(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + ), + Error::::AssetIdNotExists + ); + + assert_ok!(AssetRegistry::register_foreign_asset( + Origin::signed(CouncilAccount::get()), + Box::new(v0_location.clone()), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + )); + + assert_ok!(AssetRegistry::update_foreign_asset( + Origin::signed(CouncilAccount::get()), + 0, + Box::new(v0_location), + Box::new(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + )); + + // existed location + let new_location = VersionedMultiLocation::V0(xcm::v0::MultiLocation::X1( + xcm::v0::Junction::Parachain(2000), + )); + assert_ok!(AssetRegistry::register_foreign_asset( + Origin::signed(CouncilAccount::get()), + Box::new(new_location.clone()), + Box::new(AssetMetadata { + name: b"Token Name".to_vec(), + symbol: b"TN".to_vec(), + decimals: 12, + minimal_balance: 1, + }) + )); + assert_noop!( + AssetRegistry::update_foreign_asset( + Origin::signed(CouncilAccount::get()), + 0, + Box::new(new_location), + Box::new(AssetMetadata { + name: b"New Token Name".to_vec(), + symbol: b"NTN".to_vec(), + decimals: 13, + minimal_balance: 2, + }) + ), + Error::::MultiLocationExisted + ); + }); +} diff --git a/runtime/bifrost-kusama/Cargo.toml b/runtime/bifrost-kusama/Cargo.toml index 146eb94ac4..216f931da2 100644 --- a/runtime/bifrost-kusama/Cargo.toml +++ b/runtime/bifrost-kusama/Cargo.toml @@ -93,9 +93,9 @@ bifrost-liquidity-mining = { path = "../../pallets/liquidity-mining", default-fe bifrost-liquidity-mining-rpc-runtime-api = { path = "../../pallets/liquidity-mining/rpc/runtime-api", default-features = false } bifrost-vsbond-auction = { path = "../../pallets/vsbond-auction", default-features = false } bifrost-token-issuer = { path = "../../pallets/token-issuer", default-features = false } -bifrost-lightening-redeem= { path = "../../pallets/lightening-redeem", default-features = false } -bifrost-call-switchgear= { path = "../../pallets/call-switchgear", default-features = false } - +bifrost-lightening-redeem = { path = "../../pallets/lightening-redeem", default-features = false } +bifrost-call-switchgear = { path = "../../pallets/call-switchgear", default-features = false } +bifrost-asset-registry = { path = "../../pallets/asset-registry", default-features = false } # orml orml-currencies = { version = "0.4.1-dev", default-features = false } @@ -190,6 +190,7 @@ std = [ "bifrost-liquidity-mining-rpc-runtime-api/std", "bifrost-token-issuer/std", "bifrost-lightening-redeem/std", + "bifrost-asset-registry/std", "zenlink-protocol/std", "zenlink-protocol-runtime-api/std", "merkle-distributor/std", diff --git a/runtime/bifrost-kusama/src/lib.rs b/runtime/bifrost-kusama/src/lib.rs index bfc048c170..119359381d 100644 --- a/runtime/bifrost-kusama/src/lib.rs +++ b/runtime/bifrost-kusama/src/lib.rs @@ -69,20 +69,15 @@ use static_assertions::const_assert; /// Constant values used within the runtime. pub mod constants; +use bifrost_asset_registry::{AssetIdMaps, FixedRateOfForeignAsset}; use bifrost_flexible_fee::{ fee_dealer::{FeeDealer, FixedCurrencyFeeRate}, misc_fees::{ExtraFeeMatcher, MiscFeeHandler, NameGetter}, }; use bifrost_runtime_common::{ - cent, - constants::time::*, - dollar, micro, milli, millicent, prod_or_test, - r#impl::{ - BifrostAccountIdToMultiLocation, BifrostAssetMatcher, BifrostCurrencyIdConvert, - BifrostFilteredAssets, - }, - CouncilCollective, EnsureRootOrAllTechnicalCommittee, MoreThanHalfCouncil, - SlowAdjustingFeeUpdate, TechnicalCollective, + cent, constants::time::*, dollar, micro, milli, millicent, prod_or_test, CouncilCollective, + EnsureRootOrAllTechnicalCommittee, MoreThanHalfCouncil, SlowAdjustingFeeUpdate, + TechnicalCollective, }; use codec::{Decode, Encode, MaxEncodedLen}; use constants::currency::*; @@ -94,8 +89,8 @@ use frame_support::{ use frame_system::EnsureRoot; use hex_literal::hex; pub use node_primitives::{ - traits::CheckSubAccount, AccountId, Amount, Balance, BlockNumber, CurrencyId, ExtraFeeName, - Moment, Nonce, ParaId, PoolId, RpcContributionStatus, TokenSymbol, + traits::CheckSubAccount, AccountId, Amount, AssetIdMapping, Balance, BlockNumber, CurrencyId, + ExtraFeeName, Moment, Nonce, ParaId, PoolId, RpcContributionStatus, TokenSymbol, }; // orml imports use orml_currencies::BasicCurrencyAdapter; @@ -125,6 +120,13 @@ use zenlink_protocol::{ // Weights used in the runtime. mod weights; +mod xcm_config; + +use xcm_config::{ + BifrostAccountIdToMultiLocation, BifrostAssetMatcher, BifrostCurrencyIdConvert, + BifrostFilteredAssets, +}; + impl_opaque_keys! { pub struct SessionKeys { pub aura: Aura, @@ -1162,6 +1164,7 @@ parameter_types! { // MOVR:KSM = 2.67:1 ksm_per_second() * 267 * 10_000 //movr currency decimal as 18 ); + pub ForeignAssetUnitsPerSecond: u128 = ksm_per_second(); } pub struct ToTreasury; @@ -1191,6 +1194,7 @@ pub type Trader = ( FixedRateOfFungible, FixedRateOfFungible, FixedRateOfFungible, + FixedRateOfForeignAsset, ); pub struct XcmConfig; @@ -1339,6 +1343,10 @@ orml_traits::parameter_type_with_key! { &CurrencyId::LPToken(..) => 10 * millicent(NativeCurrencyId::get()), &CurrencyId::Token(TokenSymbol::RMRK) => 1 * micro(CurrencyId::Token(TokenSymbol::RMRK)), &CurrencyId::Token(TokenSymbol::MOVR) => 1 * micro(CurrencyId::Token(TokenSymbol::MOVR)), // MOVR has a decimals of 10e18 + CurrencyId::ForeignAsset(foreign_asset_id) => { + AssetIdMaps::::get_foreign_asset_metadata(*foreign_asset_id). + map_or(Balance::max_value(), |metatata| metatata.minimal_balance) + }, _ => Balance::max_value(), // unsupported } }; @@ -1625,6 +1633,12 @@ impl bifrost_call_switchgear::Config for Runtime { type WeightInfo = (); } +impl bifrost_asset_registry::Config for Runtime { + type Event = Event; + type Currency = Balances; + type RegisterOrigin = MoreThanHalfCouncil; +} + parameter_types! { pub ParachainAccount: AccountId = ParachainInfo::get().into_account(); pub ContributionWeight:XcmBaseWeight = RelayXcmBaseWeight::get().into(); @@ -1844,6 +1858,7 @@ construct_runtime! { SalpLite: bifrost_salp_lite::{Pallet, Call, Storage, Event, Config} = 111, CallSwitchgear: bifrost_call_switchgear::{Pallet, Storage, Call, Event} = 112, VSBondAuction: bifrost_vsbond_auction::{Pallet, Call, Storage, Event} = 113, + AssetRegistry: bifrost_asset_registry::{Pallet, Call, Storage, Event} = 114, XcmInterface: xcm_interface::{Pallet, Call, Storage, Event} = 117, } } diff --git a/runtime/bifrost-kusama/src/xcm_config.rs b/runtime/bifrost-kusama/src/xcm_config.rs new file mode 100644 index 0000000000..f8f2c0ce46 --- /dev/null +++ b/runtime/bifrost-kusama/src/xcm_config.rs @@ -0,0 +1,227 @@ +// This file is part of Bifrost. + +// Copyright (C) 2019-2022 Liebi Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use bifrost_asset_registry::AssetIdMaps; +use codec::{Decode, Encode}; +pub use cumulus_primitives_core::ParaId; +use frame_support::{ + sp_runtime::traits::{CheckedConversion, Convert}, + traits::Get, +}; +use node_primitives::{ + AccountId, AssetIdMapping, CurrencyId, CurrencyId::ForeignAsset, TokenSymbol, +}; +use orml_traits::location::Reserve; +use sp_std::{convert::TryFrom, marker::PhantomData}; +use xcm::latest::prelude::*; +use xcm_builder::NativeAsset; +use xcm_executor::traits::{FilterAssetLocation, MatchesFungible}; +use xcm_interface::traits::parachains; + +use super::Runtime; + +/// Bifrost Asset Matcher +pub struct BifrostAssetMatcher( + PhantomData<(CurrencyId, CurrencyIdConvert)>, +); + +impl MatchesFungible + for BifrostAssetMatcher +where + CurrencyIdConvert: Convert>, + Amount: TryFrom, +{ + fn matches_fungible(a: &MultiAsset) -> Option { + if let (Fungible(ref amount), Concrete(ref location)) = (&a.fun, &a.id) { + if CurrencyIdConvert::convert(location.clone()).is_some() { + return CheckedConversion::checked_from(*amount); + } + } + None + } +} + +/// Bifrost Filtered Assets +pub struct BifrostFilterAsset; + +impl FilterAssetLocation for BifrostFilterAsset { + fn filter_asset_location(asset: &MultiAsset, origin: &MultiLocation) -> bool { + if let Some(ref reserve) = asset.reserve() { + if reserve == origin { + return true; + } + } + false + } +} + +pub type BifrostFilteredAssets = (NativeAsset, BifrostFilterAsset); + +fn native_currency_location(id: CurrencyId, para_id: ParaId) -> MultiLocation { + MultiLocation::new(1, X2(Parachain(para_id.into()), GeneralKey(id.encode()))) +} + +impl> Convert> for BifrostCurrencyIdConvert { + fn convert(asset: MultiAsset) -> Option { + if let MultiAsset { id: Concrete(id), fun: Fungible(_) } = asset { + Self::convert(id) + } else { + None + } + } +} + +pub struct BifrostAccountIdToMultiLocation; +impl Convert for BifrostAccountIdToMultiLocation { + fn convert(account: AccountId) -> MultiLocation { + X1(AccountId32 { network: NetworkId::Any, id: account.into() }).into() + } +} + +pub struct BifrostCurrencyIdConvert(sp_std::marker::PhantomData); +impl> Convert> for BifrostCurrencyIdConvert { + fn convert(id: CurrencyId) -> Option { + use CurrencyId::{Native, Stable, Token, VSToken}; + match id { + Token(TokenSymbol::KSM) => Some(MultiLocation::parent()), + Native(TokenSymbol::ASG) | + Native(TokenSymbol::BNC) | + VSToken(TokenSymbol::KSM) | + Token(TokenSymbol::ZLK) => Some(native_currency_location(id, T::get())), + // Karura currencyId types + Token(TokenSymbol::KAR) => Some(MultiLocation::new( + 1, + X2( + Parachain(parachains::karura::ID), + GeneralKey(parachains::karura::KAR_KEY.to_vec()), + ), + )), + Stable(TokenSymbol::KUSD) => Some(MultiLocation::new( + 1, + X2( + Parachain(parachains::karura::ID), + GeneralKey(parachains::karura::KUSD_KEY.to_vec()), + ), + )), + Token(TokenSymbol::RMRK) => Some(MultiLocation::new( + 1, + X3( + Parachain(parachains::Statemine::ID), + PalletInstance(parachains::Statemine::PALLET_ID), + GeneralIndex(parachains::Statemine::RMRK_ID as u128), + ), + )), + // Phala Native token + Token(TokenSymbol::PHA) => + Some(MultiLocation::new(1, X1(Parachain(parachains::phala::ID)))), + // Moonriver Native token + Token(TokenSymbol::MOVR) => Some(MultiLocation::new( + 1, + X2( + Parachain(parachains::moonriver::ID), + PalletInstance(parachains::moonriver::PALLET_ID.into()), + ), + )), + ForeignAsset(foreign_asset_id) => + AssetIdMaps::::get_multi_location(foreign_asset_id), + _ => None, + } + } +} + +impl> Convert> for BifrostCurrencyIdConvert { + fn convert(location: MultiLocation) -> Option { + use CurrencyId::{Native, Stable, Token, VSToken}; + use TokenSymbol::*; + + if location == MultiLocation::parent() { + return Some(Token(KSM)); + } + + if let Some(currency_id) = AssetIdMaps::::get_currency_id(location.clone()) { + return Some(currency_id); + } + + match location { + MultiLocation { parents, interior } if parents == 1 => match interior { + X2(Parachain(id), GeneralKey(key)) if ParaId::from(id) == T::get() => { + // decode the general key + if let Ok(currency_id) = CurrencyId::decode(&mut &key[..]) { + match currency_id { + Native(TokenSymbol::ASG) | + Native(TokenSymbol::BNC) | + VSToken(TokenSymbol::KSM) | + Token(TokenSymbol::ZLK) => Some(currency_id), + _ => None, + } + } else { + None + } + }, + X2(Parachain(id), GeneralKey(key)) if id == parachains::karura::ID => { + if key == parachains::karura::KAR_KEY.to_vec() { + Some(Token(TokenSymbol::KAR)) + } else if key == parachains::karura::KUSD_KEY.to_vec() { + Some(Stable(TokenSymbol::KUSD)) + } else { + None + } + }, + X2(Parachain(id), GeneralIndex(key)) if id == parachains::Statemine::ID => { + if key == parachains::Statemine::RMRK_ID as u128 { + Some(Token(TokenSymbol::RMRK)) + } else { + None + } + }, + X3(Parachain(id), PalletInstance(index), GeneralIndex(key)) + if (id == parachains::Statemine::ID && + index == parachains::Statemine::PALLET_ID) => + if key == parachains::Statemine::RMRK_ID as u128 { + Some(Token(TokenSymbol::RMRK)) + } else { + None + }, + X1(Parachain(id)) if id == parachains::phala::ID => Some(Token(TokenSymbol::PHA)), + X2(Parachain(id), PalletInstance(index)) + if ((id == parachains::moonriver::ID) && + (index == parachains::moonriver::PALLET_ID)) => + Some(Token(TokenSymbol::MOVR)), + _ => None, + }, + MultiLocation { parents, interior } if parents == 0 => match interior { + X1(GeneralKey(key)) => { + // decode the general key + if let Ok(currency_id) = CurrencyId::decode(&mut &key[..]) { + match currency_id { + Native(TokenSymbol::ASG) | + Native(TokenSymbol::BNC) | + VSToken(TokenSymbol::KSM) | + Token(TokenSymbol::ZLK) => Some(currency_id), + _ => None, + } + } else { + None + } + }, + _ => None, + }, + _ => None, + } + } +} diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index 4302a19f55..c5b0d9a633 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -79,7 +79,7 @@ pub type EnsureRootOrAllTechnicalCommittee = EnsureOneOf< >; pub fn dollar(currency_id: CurrencyId) -> Balance { - 10u128.saturating_pow(currency_id.decimals().into()) + 10u128.saturating_pow(currency_id.decimals().unwrap_or(12).into()) } pub fn milli(currency_id: CurrencyId) -> Balance { diff --git a/scripts/bifrost-ecosystem.config.js b/scripts/bifrost-ecosystem.config.js new file mode 100644 index 0000000000..61d39cb873 --- /dev/null +++ b/scripts/bifrost-ecosystem.config.js @@ -0,0 +1,22 @@ +module.exports = { + apps : [{ + name : "bifrost-live", + exec_interpreter: "none", + exec_mode : "fork_mode", + script : "/home/bifrost/app/target/release/bifrost", + args : "--collator --execution=wasm --keystore-path /home/bifrost/app/data/keystore --chain=/home/bifrost/app/data/bifrost.json --force-authoring --parachain-id 2001 --rpc-cors=all --unsafe-ws-external --unsafe-rpc-external -- --execution=wasm --chain /home/bifrost/app/data/kusama.json" + }], + + deploy : { + production : { + "user" : "bifrost", + "host" : ["192.168.0.13", "192.168.0.14", "192.168.0.15"], + "key": "~/.ssh/deploy_rsa.pub", + "ref" : "origin/develop", + "repo" : "git@github.com/bifrost-finance/bifrost.git", + "path" : "/home/bifrost/app", + "post-setup": "make build-bifrost-release", + 'post-deploy' : 'pm2 reload scripts/bifost-ecosystem.config.js --env production' + } + } +};