diff --git a/Cargo.lock b/Cargo.lock index 0487ff80..ba40c8c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.0", + "gimli 0.27.1", ] [[package]] @@ -334,9 +334,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282" +checksum = "eff18d764974428cf3a9328e23fc5c986f5fbed46e6cd4cdf42544df5d297ec1" dependencies = [ "proc-macro2", "quote", @@ -425,7 +425,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.30.2", + "object 0.30.3", "rustc-demangle", ] @@ -709,9 +709,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-slice-cast" @@ -1541,9 +1541,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" +checksum = "b61a7545f753a88bcbe0a70de1fcc0221e10bfc752f576754fa91e663db1622e" dependencies = [ "cc", "cxxbridge-flags", @@ -1553,9 +1553,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70" +checksum = "f464457d494b5ed6905c63b0c4704842aba319084a0a3561cdc1359536b53200" dependencies = [ "cc", "codespan-reporting", @@ -1568,15 +1568,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" +checksum = "43c7119ce3a3701ed81aca8410b9acf6fc399d2629d057b87e2efa4e63a3aaea" [[package]] name = "cxxbridge-macro" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" +checksum = "65e07508b90551e610910fa648a1878991d367064997a596135b86df30daf07e" dependencies = [ "proc-macro2", "quote", @@ -2655,7 +2655,7 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", ] @@ -2678,7 +2678,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-support", "frame-system", @@ -2701,7 +2701,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "Inflector", "array-bytes", @@ -2748,7 +2748,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-support", "frame-system", @@ -2776,7 +2776,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "bitflags", "frame-metadata", @@ -2808,7 +2808,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "Inflector", "cfg-expr", @@ -2822,7 +2822,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2834,7 +2834,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "proc-macro2", "quote", @@ -2844,7 +2844,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-support", "log", @@ -2862,7 +2862,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", "sp-api", @@ -3117,9 +3117,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" [[package]] name = "glob" @@ -3585,6 +3585,7 @@ dependencies = [ "sp-runtime", "sp-std", "thiserror", + "tokens-pallet", ] [[package]] @@ -3595,7 +3596,7 @@ dependencies = [ "scale-info", "serai-primitives", "serde", - "sp-core", + "tokens-primitives", ] [[package]] @@ -3724,7 +3725,7 @@ checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" dependencies = [ "hermit-abi 0.2.6", "io-lifetimes 1.0.4", - "rustix 0.36.6", + "rustix 0.36.7", "windows-sys 0.42.0", ] @@ -4644,9 +4645,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" @@ -4689,7 +4690,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "rustix 0.36.6", + "rustix 0.36.7", ] [[package]] @@ -5222,9 +5223,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] @@ -5301,9 +5302,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.2" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c786513eb403643f2a88c244c2aaa270ef2153f55094587d0c48a3cf22a83" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] @@ -5455,7 +5456,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-benchmarking", "frame-support", @@ -5470,7 +5471,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-benchmarking", "frame-support", @@ -5485,7 +5486,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-support", "frame-system", @@ -5519,7 +5520,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-benchmarking", "frame-support", @@ -5537,7 +5538,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-support", "frame-system", @@ -5553,7 +5554,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -5569,7 +5570,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -5599,9 +5600,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.2.1" +version = "3.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "366e44391a8af4cfd6002ef6ba072bae071a96aafca98d7d448a34c5dca38b6a" +checksum = "e7ab01d0f889e957861bc65888d5ccbe82c158d0270136ba46820d43837cdf72" dependencies = [ "arrayvec 0.7.2", "bitvec 1.0.1", @@ -5614,9 +5615,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6101,9 +6102,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ "unicode-ident", ] @@ -6386,9 +6387,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -6510,11 +6511,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", "bytes", "encoding_rs", "futures-core", @@ -6740,9 +6741,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.36.6" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" dependencies = [ "bitflags", "errno", @@ -6842,7 +6843,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "log", "sp-core", @@ -6853,7 +6854,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "futures", "futures-timer", @@ -6876,7 +6877,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -6892,7 +6893,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -6907,7 +6908,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6918,7 +6919,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "array-bytes", "chrono", @@ -6958,7 +6959,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "fnv", "futures", @@ -6984,7 +6985,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "hash-db", "kvdb", @@ -7009,7 +7010,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "futures", @@ -7034,7 +7035,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "lru", "parity-scale-codec", @@ -7058,7 +7059,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -7071,7 +7072,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "log", "sc-allocator", @@ -7084,7 +7085,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "cfg-if", "libc", @@ -7101,7 +7102,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "ansi_term", "futures", @@ -7116,7 +7117,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "array-bytes", "async-trait", @@ -7131,7 +7132,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "array-bytes", "async-trait", @@ -7173,7 +7174,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "cid", "futures", @@ -7192,7 +7193,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "bitflags", @@ -7218,7 +7219,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "ahash", "futures", @@ -7236,7 +7237,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "array-bytes", "futures", @@ -7257,7 +7258,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "array-bytes", "async-trait", @@ -7289,7 +7290,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "array-bytes", "futures", @@ -7308,7 +7309,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "array-bytes", "bytes", @@ -7338,7 +7339,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "futures", "libp2p", @@ -7351,7 +7352,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -7360,7 +7361,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "futures", "jsonrpsee", @@ -7389,7 +7390,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -7408,7 +7409,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "http", "jsonrpsee", @@ -7423,7 +7424,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "array-bytes", "futures", @@ -7449,7 +7450,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "directories", @@ -7514,7 +7515,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "log", "parity-scale-codec", @@ -7525,7 +7526,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "futures", "libc", @@ -7544,7 +7545,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "chrono", "futures", @@ -7593,7 +7594,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "ansi_term", "atty", @@ -7624,7 +7625,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7635,7 +7636,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "futures", @@ -7661,7 +7662,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "futures", @@ -7675,7 +7676,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "backtrace", "futures", @@ -7904,9 +7905,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "645926f31b250a2dca3c232496c2d898d91036e45ca0e97e0e2390c54e11be36" dependencies = [ "bitflags", "core-foundation", @@ -7917,9 +7918,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -7959,14 +7960,15 @@ checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7" name = "serai-client" version = "0.1.0" dependencies = [ - "in-instructions-primitives", "jsonrpsee-server", "lazy_static", "parity-scale-codec", + "rand_core 0.6.4", + "scale-info", "scale-value", "serai-primitives", "serai-runtime", - "serde", + "sp-core", "subxt", "thiserror", "tokio", @@ -8017,6 +8019,7 @@ dependencies = [ "scale-info", "serde", "sp-core", + "sp-runtime", ] [[package]] @@ -8072,6 +8075,7 @@ dependencies = [ "sp-transaction-pool", "sp-version", "substrate-wasm-builder", + "tokens-pallet", "validator-sets-pallet", ] @@ -8346,7 +8350,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "hash-db", "log", @@ -8364,7 +8368,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "blake2", "proc-macro-crate", @@ -8376,7 +8380,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", "scale-info", @@ -8389,7 +8393,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "integer-sqrt", "num-traits", @@ -8403,7 +8407,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", "sp-api", @@ -8415,7 +8419,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "futures", "log", @@ -8433,7 +8437,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "futures", @@ -8451,7 +8455,7 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "array-bytes", "base58 0.2.0", @@ -8493,7 +8497,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "blake2", "byteorder", @@ -8507,7 +8511,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "proc-macro2", "quote", @@ -8518,7 +8522,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -8527,7 +8531,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "proc-macro2", "quote", @@ -8537,7 +8541,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "environmental", "parity-scale-codec", @@ -8548,7 +8552,7 @@ dependencies = [ [[package]] name = "sp-finality-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "finality-grandpa", "log", @@ -8566,7 +8570,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -8580,7 +8584,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "bytes", "ed25519", @@ -8605,7 +8609,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "lazy_static", "sp-core", @@ -8616,7 +8620,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "futures", @@ -8633,7 +8637,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "thiserror", "zstd", @@ -8642,7 +8646,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "sp-api", "sp-core", @@ -8652,7 +8656,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "backtrace", "lazy_static", @@ -8662,7 +8666,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "rustc-hash", "serde", @@ -8672,7 +8676,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "either", "hash256-std-hasher", @@ -8694,7 +8698,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -8712,7 +8716,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "Inflector", "proc-macro-crate", @@ -8724,7 +8728,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", "scale-info", @@ -8738,7 +8742,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", "scale-info", @@ -8750,7 +8754,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "hash-db", "log", @@ -8770,12 +8774,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "impl-serde", "parity-scale-codec", @@ -8797,7 +8801,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "futures-timer", @@ -8812,7 +8816,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", "sp-std", @@ -8824,7 +8828,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "sp-api", "sp-runtime", @@ -8833,7 +8837,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "async-trait", "log", @@ -8849,7 +8853,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "ahash", "hash-db", @@ -8872,7 +8876,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "impl-serde", "parity-scale-codec", @@ -8889,7 +8893,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -8900,7 +8904,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "impl-trait-for-tuples", "log", @@ -8913,7 +8917,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "parity-scale-codec", "scale-info", @@ -9085,7 +9089,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "platforms 2.0.0", ] @@ -9093,7 +9097,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -9112,7 +9116,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "hyper", "log", @@ -9124,7 +9128,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#c35dde519b8ee3ee0c57e452de471843a1b99339" +source = "git+https://github.com/serai-dex/substrate#ffc7ad1791f90147a3f14f4305134dbc6f8e1d76" dependencies = [ "ansi_term", "build-helper", @@ -9528,11 +9532,35 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +[[package]] +name = "tokens-pallet" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-assets", + "parity-scale-codec", + "scale-info", + "serai-primitives", + "tokens-primitives", +] + +[[package]] +name = "tokens-primitives" +version = "0.1.0" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serai-primitives", + "serde", + "sp-runtime", +] + [[package]] name = "tokio" -version = "1.24.1" +version = "1.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae" +checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb" dependencies = [ "autocfg", "bytes", @@ -9621,9 +9649,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -9894,9 +9922,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" [[package]] name = "unicode-ident" @@ -10693,9 +10721,9 @@ dependencies = [ [[package]] name = "which" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", diff --git a/Cargo.toml b/Cargo.toml index 34f7afce..2d1aea59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,9 @@ members = [ "substrate/serai/primitives", "substrate/serai/client", + "substrate/tokens/primitives", + "substrate/tokens/pallet", + "substrate/in-instructions/primitives", "substrate/in-instructions/pallet", "substrate/in-instructions/client", diff --git a/deny.toml b/deny.toml index 336ab699..a289c911 100644 --- a/deny.toml +++ b/deny.toml @@ -48,6 +48,8 @@ exceptions = [ { allow = ["AGPL-3.0"], name = "serai-processor" }, + { allow = ["AGPL-3.0"], name = "tokens-pallet" }, + { allow = ["AGPL-3.0"], name = "in-instructions-pallet" }, { allow = ["AGPL-3.0"], name = "in-instructions-client" }, diff --git a/docs/integrations/Instructions.md b/docs/integrations/Instructions.md index cec67eb2..12f1753d 100644 --- a/docs/integrations/Instructions.md +++ b/docs/integrations/Instructions.md @@ -40,10 +40,10 @@ Serai token. If an Application Call, the encoded call will be executed. ### Refundable In Instruction - - `origin` (Option\): Address, from the network of origin, -which sent coins in. - - `instruction` (InInstruction): The action to perform with the incoming -coins. + - `origin` (Option\): Address, from the network of +origin, which sent coins in. + - `instruction` (InInstruction): The action to perform with the +incoming coins. Networks may automatically provide `origin`. If they do, the instruction may still provide `origin`, overriding the automatically provided value. @@ -51,19 +51,18 @@ still provide `origin`, overriding the automatically provided value. If the instruction fails, coins are scheduled to be returned to `origin`, if provided. -### Destination - -Destination is an enum of SeraiAddress and ExternalAddress. - ### Out Instruction - - `destination` (Destination): Address to receive coins to. - - `data` (Option\): The data to call the destination with. + - `address` (ExternalAddress): Address to transfer the coins included with +this instruction to. + - `data` (Option): Data to include when transferring coins. -Transfer the coins included with this instruction to the specified address with -the specified data. No validation of external addresses/data is performed -on-chain. If data is specified for a chain not supporting data, it is silently -dropped. +No validation of external addresses/data is performed on-chain. If data is +specified for a chain not supporting data, it is silently dropped. + +### Destination + +Destination is an enum of SeraiAddress and OutInstruction. ### Shorthand @@ -80,7 +79,7 @@ covered by Shorthand. - `origin` (Option\): Refundable In Instruction's `origin`. - `coin` (Coin): Coin to swap funds for. - `minimum` (Amount): Minimum amount of `coin` to receive. - - `out` (Out Instruction): Final destination for funds. + - `out` (Destination): Final destination for funds. which expands to: diff --git a/docs/integrations/Scenarios.md b/docs/integrations/Scenarios.md deleted file mode 100644 index 5a7c8c75..00000000 --- a/docs/integrations/Scenarios.md +++ /dev/null @@ -1,98 +0,0 @@ -# Scenarios - -### Pong - -Pong has Serai receive funds, just to return them. It's a demonstration of the -in/out flow. - -``` -Shorthand::Raw( - In Instruction { - target: Incoming Asset Contract, - data: native_transfer(Incoming Asset Sender) - } -) -``` - -### Wrap - -Wrap wraps an asset from a connected chain into a Serai Asset, making it usable -with applications on Serai, such as Serai DEX. - -``` -Shorthand::Raw( - In Instruction { - target: Serai Address - } -) -``` - -### Swap SRI to Bitcoin - -For a SRI to Bitcoin swap, a SRI holder would perform an -[Application Call](../Serai.md#application-calls) to Serai DEX, purchasing -seraiBTC. Once they have seraiBTC, they are able to call `native_transfer`, -transferring the BTC underlying the seraiBTC to a specified Bitcoin address. - -### Swap Bitcoin to Monero - -For a Bitcoin to Monero swap, the following Shorthand would be used. - -``` -Shorthand::Swap { - coin: Monero, - minimum: Minimum Monero from Swap, - out: Monero Address -} -``` - - This Shorthand is expected to generally take: - - - 1 byte to identify as Swap. - - 1 byte to not override `origin`. - - 1 byte for `coin`. - - 4 bytes for `minimum`. - - 1 byte for `out`'s `destination`'s ordinal byte. - - 65 bytes for `out`'s `destination`'s address. - - 1 byte to not include `data` in `out`. - -Or 74 bytes. - -### Add Liquidity (Fresh) - -For a user who has never used Serai before, they have three requirements to add -liquidity: - - - Minting the Serai asset they wish to add liquidity for - - Acquiring Serai, as liquidity is symmetric - - Acquiring Serai for gas fees - -The Add Liquidity Shorthand enables all three of these actions, and actually -adding the liquidity, in just one transaction from a connected network. - -``` -Shorthand::AddLiquidity { - minimum: Minimum SRI from Swap, - gas: Amount of SRI to keep for gas - address: Serai address for the liquidity tokens and gas -} -``` - -For adding liquidity from Bitcoin, this Shorthand is expected to generally take: - - - 1 byte to identify as Add Liquidity. - - 1 byte to not override `origin`. - - 5 bytes for `minimum`. - - 4 bytes for `gas`. - - 32 bytes for `address`. - -Or 43 bytes. - -### Add Liquidity (SRI Holder) - -For a user who already has SRI, they solely need to have the asset they wish to -add liquidity for via their SRI. They can either purchase it from Serai DEX, or -wrap it as detailed above. - -Once they have both their SRI and the asset they wish to provide liquidity for, -they would use a Serai transaction to call the DEX, adding the liquidity. diff --git a/substrate/in-instructions/pallet/Cargo.toml b/substrate/in-instructions/pallet/Cargo.toml index 7895997e..c8c3657d 100644 --- a/substrate/in-instructions/pallet/Cargo.toml +++ b/substrate/in-instructions/pallet/Cargo.toml @@ -29,6 +29,8 @@ frame-support = { git = "https://github.com/serai-dex/substrate", default-featur serai-primitives = { path = "../../serai/primitives", default-features = false } in-instructions-primitives = { path = "../primitives", default-features = false } +tokens-pallet = { path = "../../tokens/pallet", default-features = false } + [features] std = [ "thiserror", @@ -47,5 +49,7 @@ std = [ "serai-primitives/std", "in-instructions-primitives/std", + + "tokens-pallet/std", ] default = ["std"] diff --git a/substrate/in-instructions/pallet/src/lib.rs b/substrate/in-instructions/pallet/src/lib.rs index 7b5d5f8b..ab48d564 100644 --- a/substrate/in-instructions/pallet/src/lib.rs +++ b/substrate/in-instructions/pallet/src/lib.rs @@ -13,7 +13,7 @@ use sp_inherents::{InherentIdentifier, IsFatalError}; use sp_runtime::RuntimeDebug; -use serai_primitives::{BlockNumber, BlockHash, Coin}; +use serai_primitives::{BlockNumber, BlockHash, Coin, WithAmount, Balance}; pub use in_instructions_primitives as primitives; use primitives::InInstruction; @@ -24,7 +24,7 @@ pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"ininstrs"; #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct Batch { pub id: BlockHash, - pub instructions: Vec, + pub instructions: Vec>, } #[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo, RuntimeDebug)] @@ -89,10 +89,12 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use tokens_pallet::{Config as TokensConfig, Pallet as Tokens}; + use super::*; #[pallet::config] - pub trait Config: frame_system::Config { + pub trait Config: frame_system::Config + TokensConfig { type RuntimeEvent: From> + IsType<::RuntimeEvent>; } @@ -100,6 +102,7 @@ pub mod pallet { #[pallet::generate_deposit(fn deposit_event)] pub enum Event { Batch { coin: Coin, id: BlockHash }, + Failure { coin: Coin, id: BlockHash, index: u32 }, } #[pallet::pallet] @@ -122,23 +125,43 @@ pub mod pallet { } } + impl Pallet { + fn execute(coin: Coin, instruction: WithAmount) -> Result<(), ()> { + match instruction.data { + InInstruction::Transfer(address) => { + Tokens::::mint(address, Balance { coin, amount: instruction.amount }) + } + _ => panic!("unsupported instruction"), + } + Ok(()) + } + } + #[pallet::call] impl Pallet { #[pallet::call_index(0)] - #[pallet::weight((0, DispatchClass::Mandatory))] // TODO - pub fn execute(origin: OriginFor, updates: Updates) -> DispatchResult { + #[pallet::weight((0, DispatchClass::Operational))] // TODO + pub fn update(origin: OriginFor, mut updates: Updates) -> DispatchResult { ensure_none(origin)?; assert!(!Once::::exists()); Once::::put(true); - for (coin, update) in updates.iter().enumerate() { + for (coin, update) in updates.iter_mut().enumerate() { if let Some(update) = update { let coin = coin_from_index(coin); BlockNumbers::::insert(coin, update.block_number); - for batch in &update.batches { - // TODO: EXECUTE + for batch in update.batches.iter_mut() { Self::deposit_event(Event::Batch { coin, id: batch.id }); + for (i, instruction) in batch.instructions.drain(..).enumerate() { + if Self::execute(coin, instruction).is_err() { + Self::deposit_event(Event::Failure { + coin, + id: batch.id, + index: u32::try_from(i).unwrap(), + }); + } + } } } } @@ -157,7 +180,7 @@ pub mod pallet { data .get_data::(&INHERENT_IDENTIFIER) .unwrap() - .map(|updates| Call::execute { updates }) + .map(|updates| Call::update { updates }) } // Assumes that only not yet handled batches are provided as inherent data @@ -167,7 +190,7 @@ pub mod pallet { let expected = data.get_data::(&INHERENT_IDENTIFIER).unwrap().unwrap(); // Match to be exhaustive let updates = match call { - Call::execute { ref updates } => updates, + Call::update { ref updates } => updates, _ => Err(InherentError::InvalidCall)?, }; diff --git a/substrate/in-instructions/primitives/Cargo.toml b/substrate/in-instructions/primitives/Cargo.toml index c2d4c788..fff968ce 100644 --- a/substrate/in-instructions/primitives/Cargo.toml +++ b/substrate/in-instructions/primitives/Cargo.toml @@ -16,10 +16,9 @@ scale-info = { version = "2", default-features = false, features = ["derive"] } serde = { version = "1", features = ["derive"], optional = true } -sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false } - serai-primitives = { path = "../../serai/primitives", default-features = false } +tokens-primitives = { path = "../../tokens/primitives", default-features = false } [features] -std = ["scale/std", "scale-info/std", "serde", "sp-core/std", "serai-primitives/std"] +std = ["scale/std", "scale-info/std", "serde", "serai-primitives/std", "tokens-primitives/std"] default = ["std"] diff --git a/substrate/in-instructions/primitives/src/incoming.rs b/substrate/in-instructions/primitives/src/incoming.rs deleted file mode 100644 index 0a685a11..00000000 --- a/substrate/in-instructions/primitives/src/incoming.rs +++ /dev/null @@ -1,38 +0,0 @@ -use scale::{Encode, Decode, MaxEncodedLen}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::{Serialize, Deserialize}; - -use sp_core::{ConstU32, bounded::BoundedVec}; - -use serai_primitives::SeraiAddress; - -use crate::{MAX_DATA_LEN, ExternalAddress}; - -#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub enum Application { - DEX, -} - -#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct ApplicationCall { - application: Application, - data: BoundedVec>, -} - -#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub enum InInstruction { - Transfer(SeraiAddress), - Call(ApplicationCall), -} - -#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct RefundableInInstruction { - pub origin: Option, - pub instruction: InInstruction, -} diff --git a/substrate/in-instructions/primitives/src/lib.rs b/substrate/in-instructions/primitives/src/lib.rs index befc593e..efcb85fa 100644 --- a/substrate/in-instructions/primitives/src/lib.rs +++ b/substrate/in-instructions/primitives/src/lib.rs @@ -8,40 +8,34 @@ use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; -use sp_core::{ConstU32, bounded::BoundedVec}; - -// Monero, our current longest address candidate, has a longest address of featured with payment ID -// 1 (enum) + 1 (flags) + 64 (two keys) + 8 (payment ID) = 74 -pub const MAX_ADDRESS_LEN: u32 = 74; -// Should be enough for a Uniswap v3 call -pub const MAX_DATA_LEN: u32 = 512; - -#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct ExternalAddress(BoundedVec>); -impl ExternalAddress { - #[cfg(feature = "std")] - pub fn new(address: Vec) -> Result { - Ok(ExternalAddress(address.try_into().map_err(|_| "address length exceeds {MAX_ADDRESS_LEN}")?)) - } - - pub fn address(&self) -> &[u8] { - self.0.as_ref() - } - - #[cfg(feature = "std")] - pub fn consume(self) -> Vec { - self.0.into_inner() - } -} - -// Not "in" as "in" is a keyword -mod incoming; -pub use incoming::*; - -// Not "out" to match in -mod outgoing; -pub use outgoing::*; +use serai_primitives::{SeraiAddress, ExternalAddress, Data}; mod shorthand; pub use shorthand::*; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum Application { + DEX, +} + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ApplicationCall { + application: Application, + data: Data, +} + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum InInstruction { + Transfer(SeraiAddress), + Call(ApplicationCall), +} + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct RefundableInInstruction { + pub origin: Option, + pub instruction: InInstruction, +} diff --git a/substrate/in-instructions/primitives/src/outgoing.rs b/substrate/in-instructions/primitives/src/outgoing.rs deleted file mode 100644 index 2e8cf426..00000000 --- a/substrate/in-instructions/primitives/src/outgoing.rs +++ /dev/null @@ -1,25 +0,0 @@ -use scale::{Encode, Decode, MaxEncodedLen}; -use scale_info::TypeInfo; - -#[cfg(feature = "std")] -use serde::{Serialize, Deserialize}; - -use sp_core::{ConstU32, bounded::BoundedVec}; - -use serai_primitives::SeraiAddress; - -use crate::{MAX_DATA_LEN, ExternalAddress}; - -#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub enum Destination { - Native(SeraiAddress), - External(ExternalAddress), -} - -#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct OutInstruction { - destination: Destination, - data: Option>>, -} diff --git a/substrate/in-instructions/primitives/src/shorthand.rs b/substrate/in-instructions/primitives/src/shorthand.rs index e3944510..618787b4 100644 --- a/substrate/in-instructions/primitives/src/shorthand.rs +++ b/substrate/in-instructions/primitives/src/shorthand.rs @@ -4,16 +4,18 @@ use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; -use sp_core::{ConstU32, bounded::BoundedVec}; +use serai_primitives::{Coin, Amount, SeraiAddress, ExternalAddress, Data}; -use serai_primitives::{SeraiAddress, Coin, Amount}; +use tokens_primitives::OutInstruction; -use crate::{MAX_DATA_LEN, ExternalAddress, RefundableInInstruction, InInstruction, OutInstruction}; +use crate::RefundableInInstruction; +#[cfg(feature = "std")] +use crate::InInstruction; #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub enum Shorthand { - Raw(BoundedVec>), + Raw(Data), Swap { origin: Option, coin: Coin, @@ -29,9 +31,10 @@ pub enum Shorthand { } impl Shorthand { + #[cfg(feature = "std")] pub fn transfer(origin: Option, address: SeraiAddress) -> Option { Some(Self::Raw( - BoundedVec::try_from( + Data::new( (RefundableInInstruction { origin, instruction: InInstruction::Transfer(address) }) .encode(), ) @@ -45,7 +48,7 @@ impl TryFrom for RefundableInInstruction { fn try_from(shorthand: Shorthand) -> Result { Ok(match shorthand { Shorthand::Raw(raw) => { - RefundableInInstruction::decode(&mut raw.as_ref()).map_err(|_| "invalid raw instruction")? + RefundableInInstruction::decode(&mut raw.data()).map_err(|_| "invalid raw instruction")? } Shorthand::Swap { .. } => todo!(), Shorthand::AddLiquidity { .. } => todo!(), diff --git a/substrate/node/src/chain_spec.rs b/substrate/node/src/chain_spec.rs index 63ca7a05..b440b49e 100644 --- a/substrate/node/src/chain_spec.rs +++ b/substrate/node/src/chain_spec.rs @@ -1,43 +1,42 @@ -use sp_core::{Decode, Pair as PairTrait, sr25519::Pair}; -use sp_runtime::traits::TrailingZeroInput; +use sp_core::Pair as PairTrait; use sc_service::ChainType; use serai_runtime::{ - primitives::*, tendermint::crypto::Public, WASM_BINARY, opaque::SessionKeys, GenesisConfig, - SystemConfig, BalancesConfig, AssetsConfig, ValidatorSetsConfig, SessionConfig, + primitives::*, tokens::primitives::ADDRESS as TOKENS_ADDRESS, tendermint::crypto::Public, + WASM_BINARY, opaque::SessionKeys, GenesisConfig, SystemConfig, BalancesConfig, AssetsConfig, + ValidatorSetsConfig, SessionConfig, }; pub type ChainSpec = sc_service::GenericChainSpec; -fn insecure_pair_from_name(name: &'static str) -> Pair { - Pair::from_string(&format!("//{name}"), None).unwrap() -} - -fn address_from_name(name: &'static str) -> SeraiAddress { +fn account_from_name(name: &'static str) -> PublicKey { insecure_pair_from_name(name).public() } fn testnet_genesis( wasm_binary: &[u8], validators: &[&'static str], - endowed_accounts: Vec, + endowed_accounts: Vec, ) -> GenesisConfig { let session_key = |name| { - let key = address_from_name(name); + let key = account_from_name(name); (key, key, SessionKeys { tendermint: Public::from(key) }) }; - // TODO: Replace with a call to the pallet to ask for its account - let owner = SeraiAddress::decode(&mut TrailingZeroInput::new(b"tokens")).unwrap(); - GenesisConfig { system: SystemConfig { code: wasm_binary.to_vec() }, + balances: BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), }, + transaction_payment: Default::default(), + assets: AssetsConfig { - assets: [BITCOIN, ETHER, DAI, MONERO].iter().map(|coin| (*coin, owner, true, 1)).collect(), + assets: [BITCOIN, ETHER, DAI, MONERO] + .iter() + .map(|coin| (*coin, TOKENS_ADDRESS.into(), true, 1)) + .collect(), metadata: vec![ (BITCOIN, b"Bitcoin".to_vec(), b"BTC".to_vec(), 8), // Reduce to 8 decimals to feasibly fit within u64 (instead of its native u256) @@ -47,14 +46,13 @@ fn testnet_genesis( ], accounts: vec![], }, - transaction_payment: Default::default(), - validator_sets: ValidatorSetsConfig { - bond: Amount(1_000_000) * COIN, - coins: vec![BITCOIN, ETHER, DAI, MONERO], - participants: validators.iter().map(|name| address_from_name(name)).collect(), - }, session: SessionConfig { keys: validators.iter().map(|name| session_key(*name)).collect() }, + validator_sets: ValidatorSetsConfig { + bond: Amount(1_000_000 * 10_u64.pow(8)), + coins: vec![BITCOIN, ETHER, DAI, MONERO], + participants: validators.iter().map(|name| account_from_name(name)).collect(), + }, } } @@ -72,18 +70,18 @@ pub fn development_config() -> Result { wasm_binary, &["Alice"], vec![ - address_from_name("Alice"), - address_from_name("Bob"), - address_from_name("Charlie"), - address_from_name("Dave"), - address_from_name("Eve"), - address_from_name("Ferdie"), - address_from_name("Alice//stash"), - address_from_name("Bob//stash"), - address_from_name("Charlie//stash"), - address_from_name("Dave//stash"), - address_from_name("Eve//stash"), - address_from_name("Ferdie//stash"), + account_from_name("Alice"), + account_from_name("Bob"), + account_from_name("Charlie"), + account_from_name("Dave"), + account_from_name("Eve"), + account_from_name("Ferdie"), + account_from_name("Alice//stash"), + account_from_name("Bob//stash"), + account_from_name("Charlie//stash"), + account_from_name("Dave//stash"), + account_from_name("Eve//stash"), + account_from_name("Ferdie//stash"), ], ) }, @@ -116,18 +114,18 @@ pub fn testnet_config() -> Result { wasm_binary, &["Alice", "Bob", "Charlie"], vec![ - address_from_name("Alice"), - address_from_name("Bob"), - address_from_name("Charlie"), - address_from_name("Dave"), - address_from_name("Eve"), - address_from_name("Ferdie"), - address_from_name("Alice//stash"), - address_from_name("Bob//stash"), - address_from_name("Charlie//stash"), - address_from_name("Dave//stash"), - address_from_name("Eve//stash"), - address_from_name("Ferdie//stash"), + account_from_name("Alice"), + account_from_name("Bob"), + account_from_name("Charlie"), + account_from_name("Dave"), + account_from_name("Eve"), + account_from_name("Ferdie"), + account_from_name("Alice//stash"), + account_from_name("Bob//stash"), + account_from_name("Charlie//stash"), + account_from_name("Dave//stash"), + account_from_name("Eve//stash"), + account_from_name("Ferdie//stash"), ], ) }, diff --git a/substrate/node/src/command_helper.rs b/substrate/node/src/command_helper.rs index 7d944b69..beea5b12 100644 --- a/substrate/node/src/command_helper.rs +++ b/substrate/node/src/command_helper.rs @@ -67,7 +67,7 @@ pub fn create_benchmark_extrinsic( UncheckedExtrinsic::new_signed( call.clone(), - sender.public(), + sender.public().into(), SignedPayload::from_raw( call, extra.clone(), diff --git a/substrate/node/src/rpc.rs b/substrate/node/src/rpc.rs index c5df739d..e0a6c16c 100644 --- a/substrate/node/src/rpc.rs +++ b/substrate/node/src/rpc.rs @@ -6,7 +6,11 @@ use sp_blockchain::{Error as BlockchainError, HeaderBackend, HeaderMetadata}; use sp_block_builder::BlockBuilder; use sp_api::ProvideRuntimeApi; -use serai_runtime::{primitives::SeraiAddress, opaque::Block, Balance, Index}; +use serai_runtime::{ + primitives::{SubstrateAmount, PublicKey}, + opaque::Block, + Index, +}; pub use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; @@ -29,8 +33,8 @@ pub fn create_full< deps: FullDeps, ) -> Result, Box> where - C::Api: substrate_frame_rpc_system::AccountNonceApi - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + C::Api: substrate_frame_rpc_system::AccountNonceApi + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + BlockBuilder, { use substrate_frame_rpc_system::{System, SystemApiServer}; diff --git a/substrate/node/src/service.rs b/substrate/node/src/service.rs index f6aa1e1f..d4a6b4f9 100644 --- a/substrate/node/src/service.rs +++ b/substrate/node/src/service.rs @@ -76,9 +76,9 @@ impl TendermintClientMinimal for TendermintValidatorFirm { // guaranteed not to grow the block? const PROPOSED_BLOCK_SIZE_LIMIT: usize = { BLOCK_SIZE as usize }; // 3 seconds - const BLOCK_PROCESSING_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2 / 1000) as u32 }; + const BLOCK_PROCESSING_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2) as u32 }; // 1 second - const LATENCY_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2 / 3 / 1000) as u32 }; + const LATENCY_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2 / 3) as u32 }; type Block = Block; type Backend = sc_client_db::Backend; @@ -101,7 +101,7 @@ impl TendermintValidator for TendermintValidatorFirm { pub fn new_partial( config: &Configuration, ) -> Result<(TendermintImport, PartialComponents), ServiceError> { - debug_assert_eq!(TARGET_BLOCK_TIME, 6000); + debug_assert_eq!(TARGET_BLOCK_TIME, 6); if config.keystore_remote.is_some() { return Err(ServiceError::Other("Remote Keystores are not supported".to_string())); diff --git a/substrate/runtime/Cargo.toml b/substrate/runtime/Cargo.toml index a379fdb9..74c305e7 100644 --- a/substrate/runtime/Cargo.toml +++ b/substrate/runtime/Cargo.toml @@ -41,6 +41,7 @@ pallet-balances = { git = "https://github.com/serai-dex/substrate", default-feat pallet-assets = { git = "https://github.com/serai-dex/substrate", default-features = false } pallet-transaction-payment = { git = "https://github.com/serai-dex/substrate", default-features = false } +tokens-pallet = { path = "../tokens/pallet", default-features = false } in-instructions-pallet = { path = "../in-instructions/pallet", default-features = false } validator-sets-pallet = { path = "../validator-sets/pallet", default-features = false } @@ -78,9 +79,10 @@ std = [ "serai-primitives/std", "pallet-balances/std", - "pallet-assets/std", "pallet-transaction-payment/std", + "pallet-assets/std", + "tokens-pallet/std", "in-instructions-pallet/std", "validator-sets-pallet/std", diff --git a/substrate/runtime/src/lib.rs b/substrate/runtime/src/lib.rs index 91d48750..cd5c6c91 100644 --- a/substrate/runtime/src/lib.rs +++ b/substrate/runtime/src/lib.rs @@ -16,6 +16,7 @@ pub use pallet_balances as balances; pub use pallet_transaction_payment as transaction_payment; pub use pallet_assets as assets; +pub use tokens_pallet as tokens; pub use in_instructions_pallet as in_instructions; pub use validator_sets_pallet as validator_sets; @@ -33,15 +34,15 @@ use sp_version::NativeVersion; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, KeyTypeId, - traits::{Convert, OpaqueKeys, IdentityLookup, BlakeTwo256, Block as BlockT}, + traits::{Convert, OpaqueKeys, BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, Perbill, }; -use primitives::{PublicKey, Signature, SeraiAddress, Coin}; +use primitives::{PublicKey, SeraiAddress, AccountLookup, Signature, SubstrateAmount, Coin}; use support::{ - traits::{ConstU8, ConstU32, ConstU64}, + traits::{ConstU8, ConstU32, ConstU64, Contains}, weights::{ constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND}, IdentityFee, Weight, @@ -56,14 +57,6 @@ use session::PeriodicSessions; /// An index to a block. pub type BlockNumber = u32; -/// Balance of an account. -// Distinct from serai-primitives Amount due to Substrate's requirements on this type. -// If Amount could be dropped in here, it would be. -// While Amount could have all the necessary traits implemented, not only are they many, yet it'd -// make Amount a larger type, providing more operations than desired. -// The current type's minimalism sets clear bounds on usage. -pub type Balance = u64; - /// Index of a transaction in the chain, for a given account. pub type Index = u32; @@ -104,10 +97,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // 1 MB pub const BLOCK_SIZE: u32 = 1024 * 1024; // 6 seconds -pub const TARGET_BLOCK_TIME: u64 = 6000; +pub const TARGET_BLOCK_TIME: u64 = 6; /// Measured in blocks. -pub const MINUTES: BlockNumber = 60_000 / (TARGET_BLOCK_TIME as BlockNumber); +pub const MINUTES: BlockNumber = 60 / (TARGET_BLOCK_TIME as BlockNumber); pub const HOURS: BlockNumber = MINUTES * 60; pub const DAYS: BlockNumber = HOURS * 24; @@ -134,13 +127,44 @@ parameter_types! { ); } +pub struct CallFilter; +impl Contains for CallFilter { + fn contains(call: &RuntimeCall) -> bool { + if let RuntimeCall::Balances(call) = call { + return matches!(call, balances::Call::transfer { .. } | balances::Call::transfer_all { .. }); + } + + if let RuntimeCall::Assets(call) = call { + return matches!( + call, + assets::Call::approve_transfer { .. } | + assets::Call::cancel_approval { .. } | + assets::Call::transfer { .. } | + assets::Call::transfer_approved { .. } + ); + } + if let RuntimeCall::Tokens(call) = call { + return matches!(call, tokens::Call::burn { .. }); + } + if let RuntimeCall::InInstructions(call) = call { + return matches!(call, in_instructions::Call::update { .. }); + } + + if let RuntimeCall::ValidatorSets(call) = call { + return matches!(call, validator_sets::Call::vote { .. }); + } + + false + } +} + impl system::Config for Runtime { - type BaseCallFilter = support::traits::Everything; + type BaseCallFilter = CallFilter; type BlockWeights = BlockWeights; type BlockLength = BlockLength; - type AccountId = SeraiAddress; + type AccountId = PublicKey; type RuntimeCall = RuntimeCall; - type Lookup = IdentityLookup; + type Lookup = AccountLookup; type Index = Index; type BlockNumber = BlockNumber; type Hash = Hash; @@ -157,7 +181,7 @@ impl system::Config for Runtime { type OnKilledAccount = (); type OnSetCode = (); - type AccountData = balances::AccountData; + type AccountData = balances::AccountData; type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; // TODO: Remove for Bech32m @@ -168,7 +192,7 @@ impl balances::Config for Runtime { type MaxLocks = ConstU32<50>; type MaxReserves = (); type ReserveIdentifier = [u8; 8]; - type Balance = Balance; + type Balance = SubstrateAmount; type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<500>; @@ -176,9 +200,18 @@ impl balances::Config for Runtime { type WeightInfo = balances::weights::SubstrateWeight; } +impl transaction_payment::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnChargeTransaction = CurrencyAdapter; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; + type FeeMultiplierUpdate = (); +} + impl assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Balance = Balance; + type Balance = SubstrateAmount; type Currency = Balances; type AssetId = Coin; @@ -186,8 +219,8 @@ impl assets::Config for Runtime { type StringLimit = ConstU32<32>; // Don't allow anyone to create assets - type CreateOrigin = support::traits::AsEnsureOriginWithArg>; - type ForceOrigin = system::EnsureRoot; + type CreateOrigin = support::traits::AsEnsureOriginWithArg>; + type ForceOrigin = system::EnsureRoot; // Don't charge fees nor kill accounts type RemoveItemsLimit = ConstU32<0>; @@ -207,13 +240,8 @@ impl assets::Config for Runtime { type BenchmarkHelper = (); } -impl transaction_payment::Config for Runtime { +impl tokens::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type OnChargeTransaction = CurrencyAdapter; - type OperationalFeeMultiplier = ConstU8<5>; - type WeightToFee = IdentityFee; - type LengthToFee = IdentityFee; - type FeeMultiplierUpdate = (); } impl in_instructions::Config for Runtime { @@ -236,7 +264,7 @@ impl validator_sets::Config for Runtime { impl session::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type ValidatorId = SeraiAddress; + type ValidatorId = PublicKey; type ValidatorIdOf = IdentityValidatorIdOf; type ShouldEndSession = Sessions; type NextSessionRotation = Sessions; @@ -283,6 +311,7 @@ construct_runtime!( TransactionPayment: transaction_payment, Assets: assets, + Tokens: tokens, InInstructions: in_instructions, ValidatorSets: validator_sets, @@ -381,31 +410,31 @@ sp_api::impl_runtime_apis! { } fn validators() -> Vec { - Session::validators() + Session::validators().drain(..).map(Into::into).collect() } } - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: SeraiAddress) -> Index { + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: PublicKey) -> Index { System::account_nonce(account) } } impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< Block, - Balance + SubstrateAmount > for Runtime { fn query_info( uxt: ::Extrinsic, len: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { TransactionPayment::query_info(uxt, len) } fn query_fee_details( uxt: ::Extrinsic, len: u32, - ) -> transaction_payment::FeeDetails { + ) -> transaction_payment::FeeDetails { TransactionPayment::query_fee_details(uxt, len) } } diff --git a/substrate/serai/client/Cargo.toml b/substrate/serai/client/Cargo.toml index ca35be61..f26f2485 100644 --- a/substrate/serai/client/Cargo.toml +++ b/substrate/serai/client/Cargo.toml @@ -15,19 +15,22 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] thiserror = "1" -serde = { version = "1", features = ["derive"] } - scale = { package = "parity-scale-codec", version = "3" } +scale-info = "2" scale-value = "0.6" -subxt = "0.25" + +sp-core = { git = "https://github.com/serai-dex/substrate", version = "7" } serai-primitives = { path = "../primitives", version = "0.1" } -in-instructions-primitives = { path = "../../in-instructions/primitives", version = "0.1" } serai-runtime = { path = "../../runtime", version = "0.1" } +subxt = "0.25" + [dev-dependencies] lazy_static = "1" +rand_core = "0.6" + tokio = "1" jsonrpsee-server = "0.16" diff --git a/substrate/serai/client/metadata.json b/substrate/serai/client/metadata.json new file mode 100644 index 00000000..e69de29b diff --git a/substrate/serai/client/src/in_instructions.rs b/substrate/serai/client/src/in_instructions.rs index 8c26b80a..9187d7a4 100644 --- a/substrate/serai/client/src/in_instructions.rs +++ b/substrate/serai/client/src/in_instructions.rs @@ -1,15 +1,9 @@ -use scale::Decode; - -use serai_runtime::{ - support::traits::PalletInfo as PalletInfoTrait, PalletInfo, in_instructions, InInstructions, - Runtime, -}; - -pub use in_instructions_primitives as primitives; +use serai_runtime::{in_instructions, InInstructions, Runtime}; +pub use in_instructions::primitives; use crate::{ primitives::{Coin, BlockNumber}, - Serai, SeraiError, + Serai, SeraiError, scale_value, }; const PALLET: &str = "InInstructions"; @@ -21,22 +15,11 @@ impl Serai { &self, block: [u8; 32], ) -> Result, SeraiError> { - let mut res = vec![]; - for event in - self.0.events().at(Some(block.into())).await.map_err(|_| SeraiError::RpcError)?.iter() - { - let event = event.map_err(|_| SeraiError::InvalidRuntime)?; - if PalletInfo::index::().unwrap() == usize::from(event.pallet_index()) { - let mut with_variant: &[u8] = - &[[event.variant_index()].as_ref(), event.field_bytes()].concat(); - let event = - InInstructionsEvent::decode(&mut with_variant).map_err(|_| SeraiError::InvalidRuntime)?; - if matches!(event, InInstructionsEvent::Batch { .. }) { - res.push(event); - } - } - } - Ok(res) + self + .events::(block, |event| { + matches!(event, InInstructionsEvent::Batch { .. }) + }) + .await } pub async fn get_coin_block_number( @@ -44,6 +27,11 @@ impl Serai { coin: Coin, block: [u8; 32], ) -> Result { - Ok(self.storage(PALLET, "BlockNumbers", Some(coin), block).await?.unwrap_or(BlockNumber(0))) + Ok( + self + .storage(PALLET, "BlockNumbers", Some(vec![scale_value(coin)]), block) + .await? + .unwrap_or(BlockNumber(0)), + ) } } diff --git a/substrate/serai/client/src/lib.rs b/substrate/serai/client/src/lib.rs index 36bfd8a5..8cf6dec8 100644 --- a/substrate/serai/client/src/lib.rs +++ b/substrate/serai/client/src/lib.rs @@ -1,19 +1,36 @@ use thiserror::Error; -use serde::Serialize; -use scale::Decode; +use scale::{Encode, Decode}; +mod scale_value; +pub(crate) use crate::scale_value::{scale_value, scale_composite}; +use ::scale_value::Value; -use subxt::{tx::BaseExtrinsicParams, Config as SubxtConfig, OnlineClient}; +use subxt::{ + utils::Encoded, + tx::{ + Signer, DynamicTxPayload, BaseExtrinsicParams, BaseExtrinsicParamsBuilder, TxClient, + }, + Config as SubxtConfig, OnlineClient, +}; pub use serai_primitives as primitives; use primitives::{Signature, SeraiAddress}; -use serai_runtime::{system::Config, Runtime}; +use serai_runtime::{ + system::Config, support::traits::PalletInfo as PalletInfoTrait, PalletInfo, Runtime, +}; +pub mod tokens; pub mod in_instructions; +#[derive(Clone, Copy, PartialEq, Eq, Default, Debug, Encode, Decode)] +pub struct Tip { + #[codec(compact)] + pub tip: u64, +} + #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub(crate) struct SeraiConfig; +pub struct SeraiConfig; impl SubxtConfig for SeraiConfig { type BlockNumber = ::BlockNumber; @@ -28,7 +45,7 @@ impl SubxtConfig for SeraiConfig { type Header = ::Header; type Signature = Signature; - type ExtrinsicParams = BaseExtrinsicParams; + type ExtrinsicParams = BaseExtrinsicParams; } #[derive(Clone, Error, Debug)] @@ -47,21 +64,16 @@ impl Serai { Ok(Serai(OnlineClient::::from_url(url).await.map_err(|_| SeraiError::RpcError)?)) } - async fn storage( + async fn storage( &self, pallet: &'static str, name: &'static str, - key: Option, + keys: Option>, block: [u8; 32], ) -> Result, SeraiError> { - let mut keys = vec![]; - if let Some(key) = key { - keys.push(scale_value::serde::to_value(key).unwrap()); - } - let storage = self.0.storage(); - let address = subxt::dynamic::storage(pallet, name, keys); - debug_assert!(storage.validate(&address).is_ok()); + let address = subxt::dynamic::storage(pallet, name, keys.unwrap_or(vec![])); + debug_assert!(storage.validate(&address).is_ok(), "invalid storage address"); storage .fetch(&address, Some(block.into())) @@ -71,7 +83,46 @@ impl Serai { .transpose() } + async fn events( + &self, + block: [u8; 32], + filter: impl Fn(&E) -> bool, + ) -> Result, SeraiError> { + let mut res = vec![]; + for event in + self.0.events().at(Some(block.into())).await.map_err(|_| SeraiError::RpcError)?.iter() + { + let event = event.map_err(|_| SeraiError::InvalidRuntime)?; + if PalletInfo::index::

().unwrap() == usize::from(event.pallet_index()) { + let mut with_variant: &[u8] = + &[[event.variant_index()].as_ref(), event.field_bytes()].concat(); + let event = E::decode(&mut with_variant).map_err(|_| SeraiError::InvalidRuntime)?; + if filter(&event) { + res.push(event); + } + } + } + Ok(res) + } + pub async fn get_latest_block_hash(&self) -> Result<[u8; 32], SeraiError> { Ok(self.0.rpc().finalized_head().await.map_err(|_| SeraiError::RpcError)?.into()) } + + pub fn sign>( + &self, + signer: &S, + payload: &DynamicTxPayload<'static>, + nonce: u32, + params: BaseExtrinsicParamsBuilder, + ) -> Result { + TxClient::new(self.0.offline()) + .create_signed_with_nonce(payload, signer, nonce, params) + .map(|tx| Encoded(tx.into_encoded())) + .map_err(|_| SeraiError::InvalidRuntime) + } + + pub async fn publish(&self, tx: &Encoded) -> Result<[u8; 32], SeraiError> { + self.0.rpc().submit_extrinsic(tx).await.map(Into::into).map_err(|_| SeraiError::RpcError) + } } diff --git a/substrate/serai/client/src/scale_value.rs b/substrate/serai/client/src/scale_value.rs new file mode 100644 index 00000000..0e74b1b2 --- /dev/null +++ b/substrate/serai/client/src/scale_value.rs @@ -0,0 +1,18 @@ +use ::scale::Encode; +use scale_info::{MetaType, TypeInfo, Registry, PortableRegistry}; +use scale_value::{Composite, ValueDef, Value, scale}; + +pub(crate) fn scale_value(value: V) -> Value { + let mut registry = Registry::new(); + let id = registry.register_type(&MetaType::new::()).id(); + let registry = PortableRegistry::from(registry); + scale::decode_as_type(&mut value.encode().as_ref(), id, ®istry).unwrap().remove_context() +} + +pub(crate) fn scale_composite(value: V) -> Composite<()> { + match scale_value(value).value { + ValueDef::Composite(composite) => composite, + ValueDef::Variant(variant) => variant.values, + _ => panic!("not composite"), + } +} diff --git a/substrate/serai/client/src/tokens.rs b/substrate/serai/client/src/tokens.rs new file mode 100644 index 00000000..f77e34e1 --- /dev/null +++ b/substrate/serai/client/src/tokens.rs @@ -0,0 +1,68 @@ +use serai_runtime::{ + primitives::{SeraiAddress, SubstrateAmount, Amount, Coin, Balance}, + assets::{AssetDetails, AssetAccount}, + tokens, Tokens, Runtime, +}; +pub use tokens::primitives; +use primitives::OutInstruction; + +use subxt::tx::{self, DynamicTxPayload}; + +use crate::{Serai, SeraiError, scale_value, scale_composite}; + +const PALLET: &str = "Tokens"; + +pub type TokensEvent = tokens::Event; + +impl Serai { + pub async fn get_mint_events(&self, block: [u8; 32]) -> Result, SeraiError> { + self.events::(block, |event| matches!(event, TokensEvent::Mint { .. })).await + } + + pub async fn get_token_supply(&self, block: [u8; 32], coin: Coin) -> Result { + Ok(Amount( + self + .storage::>( + "Assets", + "Asset", + Some(vec![scale_value(coin)]), + block, + ) + .await? + .map(|token| token.supply) + .unwrap_or(0), + )) + } + + pub async fn get_token_balance( + &self, + block: [u8; 32], + coin: Coin, + address: SeraiAddress, + ) -> Result { + Ok(Amount( + self + .storage::>( + "Assets", + "Account", + Some(vec![scale_value(coin), scale_value(address)]), + block, + ) + .await? + .map(|account| account.balance) + .unwrap_or(0), + )) + } + + pub fn burn(balance: Balance, instruction: OutInstruction) -> DynamicTxPayload<'static> { + tx::dynamic( + PALLET, + "burn", + scale_composite(tokens::Call::::burn { balance, instruction }), + ) + } + + pub async fn get_burn_events(&self, block: [u8; 32]) -> Result, SeraiError> { + self.events::(block, |event| matches!(event, TokensEvent::Burn { .. })).await + } +} diff --git a/substrate/serai/client/tests/burn.rs b/substrate/serai/client/tests/burn.rs new file mode 100644 index 00000000..9e58ed4b --- /dev/null +++ b/substrate/serai/client/tests/burn.rs @@ -0,0 +1,79 @@ +use core::time::Duration; + +use rand_core::{RngCore, OsRng}; + +use sp_core::Pair; +use serai_runtime::in_instructions::{Batch, Update}; + +use tokio::time::sleep; + +use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; + +use serai_client::{ + primitives::{ + BITCOIN, BlockNumber, BlockHash, SeraiAddress, Amount, WithAmount, Balance, Data, + ExternalAddress, insecure_pair_from_name, + }, + in_instructions::primitives::InInstruction, + tokens::{primitives::OutInstruction, TokensEvent}, + Serai, +}; + +mod runner; +use runner::{URL, provide_updates}; + +serai_test!( + async fn burn() { + let coin = BITCOIN; + let mut id = BlockHash([0; 32]); + OsRng.fill_bytes(&mut id.0); + let block_number = BlockNumber(u32::try_from(OsRng.next_u64() >> 32).unwrap()); + + let pair = insecure_pair_from_name("Alice"); + let public = pair.public(); + let address = SeraiAddress::from(public); + + let amount = Amount(OsRng.next_u64()); + let balance = Balance { coin, amount }; + + let mut rand_bytes = vec![0; 32]; + OsRng.fill_bytes(&mut rand_bytes); + let external_address = ExternalAddress::new(rand_bytes).unwrap(); + + let mut rand_bytes = vec![0; 32]; + OsRng.fill_bytes(&mut rand_bytes); + let data = Data::new(rand_bytes).unwrap(); + + let batch = Batch { + id, + instructions: vec![WithAmount { data: InInstruction::Transfer(address), amount }], + }; + let update = Update { block_number, batches: vec![batch] }; + let block = provide_updates(vec![Some(update)]).await; + + let serai = Serai::new(URL).await.unwrap(); + assert_eq!(serai.get_token_balance(block, coin, address).await.unwrap(), amount); + + let out = OutInstruction { address: external_address, data: Some(data) }; + let burn = Serai::burn(balance, out.clone()); + + let signer = PairSigner::new(pair); + serai + .publish(&serai.sign(&signer, &burn, 0, BaseExtrinsicParamsBuilder::new()).unwrap()) + .await + .unwrap(); + + loop { + let block = serai.get_latest_block_hash().await.unwrap(); + let events = serai.get_burn_events(block).await.unwrap(); + if events.is_empty() { + sleep(Duration::from_millis(50)).await; + continue; + } + assert_eq!(events, vec![TokensEvent::Burn { address, balance, instruction: out }]); + assert_eq!(serai.get_token_supply(block, coin).await.unwrap(), Amount(0)); + assert_eq!(serai.get_token_balance(block, coin, address).await.unwrap(), Amount(0)); + break; + } + } +); diff --git a/substrate/serai/client/tests/runner.rs b/substrate/serai/client/tests/runner.rs index e5ed4542..1e9e7444 100644 --- a/substrate/serai/client/tests/runner.rs +++ b/substrate/serai/client/tests/runner.rs @@ -1,6 +1,14 @@ +use core::time::Duration; +use std::sync::Arc; + use lazy_static::lazy_static; -use tokio::sync::Mutex; +use tokio::{sync::Mutex, time::sleep}; + +use serai_runtime::in_instructions::Update; +use serai_client::{primitives::Coin, in_instructions::InInstructionsEvent, Serai}; + +use jsonrpsee_server::RpcModule; pub const URL: &str = "ws://127.0.0.1:9944"; @@ -8,6 +16,73 @@ lazy_static! { pub static ref SEQUENTIAL: Mutex<()> = Mutex::new(()); } +#[allow(dead_code)] +pub async fn provide_updates(updates: Vec>) -> [u8; 32] { + let done = Arc::new(Mutex::new(false)); + let done_clone = done.clone(); + let updates_clone = updates.clone(); + + let mut rpc = RpcModule::new(()); + rpc + .register_async_method("processor_coinUpdates", move |_, _| { + let done_clone = done_clone.clone(); + let updates_clone = updates_clone.clone(); + async move { + // Sleep to prevent a race condition where we submit the inherents for this block and the + // next one, then remove them, making them unverifiable, causing the node to panic for + // being self-malicious + sleep(Duration::from_millis(500)).await; + if !*done_clone.lock().await { + Ok(updates_clone) + } else { + Ok(vec![]) + } + } + }) + .unwrap(); + let _handle = jsonrpsee_server::ServerBuilder::default() + .build("127.0.0.1:5134") + .await + .unwrap() + .start(rpc) + .unwrap(); + + let serai = Serai::new(URL).await.unwrap(); + loop { + let latest = serai.get_latest_block_hash().await.unwrap(); + let mut batches = serai.get_batch_events(latest).await.unwrap(); + if batches.is_empty() { + sleep(Duration::from_millis(50)).await; + continue; + } + *done.lock().await = true; + + for (index, update) in updates.iter().enumerate() { + if let Some(update) = update { + let coin_by_index = Coin(u32::try_from(index).unwrap() + 1); + + for expected in &update.batches { + match batches.swap_remove(0) { + InInstructionsEvent::Batch { coin, id } => { + assert_eq!(coin, coin_by_index); + assert_eq!(expected.id, id); + } + _ => panic!("get_batches returned non-batch"), + } + } + assert_eq!( + serai.get_coin_block_number(coin_by_index, latest).await.unwrap(), + update.block_number + ); + } + } + // This will fail if there were more batch events than expected + assert!(batches.is_empty()); + + return latest; + } +} + #[macro_export] macro_rules! serai_test { ($(async fn $name: ident() $body: block)*) => { diff --git a/substrate/serai/client/tests/updates.rs b/substrate/serai/client/tests/updates.rs index ba97bc73..05c30c83 100644 --- a/substrate/serai/client/tests/updates.rs +++ b/substrate/serai/client/tests/updates.rs @@ -1,60 +1,45 @@ -use core::time::Duration; - -use tokio::time::sleep; +use rand_core::{RngCore, OsRng}; use serai_runtime::in_instructions::{Batch, Update}; -use jsonrpsee_server::RpcModule; - use serai_client::{ - primitives::{BlockNumber, BlockHash, SeraiAddress, BITCOIN}, + primitives::{BITCOIN, BlockNumber, BlockHash, SeraiAddress, Amount, WithAmount, Balance}, + tokens::TokensEvent, in_instructions::{primitives::InInstruction, InInstructionsEvent}, Serai, }; mod runner; -use runner::URL; +use runner::{URL, provide_updates}; serai_test!( - async fn publish_update() { - let mut rpc = RpcModule::new(()); - rpc - .register_async_method("processor_coinUpdates", |_, _| async move { - let batch = Batch { - id: BlockHash([0xaa; 32]), - instructions: vec![InInstruction::Transfer(SeraiAddress::from_raw([0xff; 32]))], - }; + async fn publish_updates() { + let coin = BITCOIN; + let mut id = BlockHash([0; 32]); + OsRng.fill_bytes(&mut id.0); + let block_number = BlockNumber(u32::try_from(OsRng.next_u64() >> 32).unwrap()); - Ok(vec![Some(Update { block_number: BlockNumber(123), batches: vec![batch] })]) - }) - .unwrap(); + let mut address = SeraiAddress::new([0; 32]); + OsRng.fill_bytes(&mut address.0); + let amount = Amount(OsRng.next_u64()); - let _handle = jsonrpsee_server::ServerBuilder::default() - .build("127.0.0.1:5134") - .await - .unwrap() - .start(rpc) - .unwrap(); + let batch = Batch { + id, + instructions: vec![WithAmount { data: InInstruction::Transfer(address), amount }], + }; + let update = Update { block_number, batches: vec![batch] }; + let block = provide_updates(vec![Some(update)]).await; let serai = Serai::new(URL).await.unwrap(); - loop { - let latest = serai.get_latest_block_hash().await.unwrap(); - let batches = serai.get_batch_events(latest).await.unwrap(); - if let Some(batch) = batches.get(0) { - match batch { - InInstructionsEvent::Batch { coin, id } => { - assert_eq!(coin, &BITCOIN); - assert_eq!(id, &BlockHash([0xaa; 32])); - assert_eq!( - serai.get_coin_block_number(BITCOIN, latest).await.unwrap(), - BlockNumber(123) - ); - return; - } - _ => panic!("get_batches returned non-batch"), - } - } - sleep(Duration::from_millis(50)).await; - } + let batches = serai.get_batch_events(block).await.unwrap(); + assert_eq!(batches, vec![InInstructionsEvent::Batch { coin, id }]); + assert_eq!(serai.get_coin_block_number(coin, block).await.unwrap(), block_number); + + assert_eq!( + serai.get_mint_events(block).await.unwrap(), + vec![TokensEvent::Mint { address, balance: Balance { coin, amount } }] + ); + assert_eq!(serai.get_token_supply(block, coin).await.unwrap(), amount); + assert_eq!(serai.get_token_balance(block, coin, address).await.unwrap(), amount); } ); diff --git a/substrate/serai/primitives/Cargo.toml b/substrate/serai/primitives/Cargo.toml index 5d6a1490..303a27b0 100644 --- a/substrate/serai/primitives/Cargo.toml +++ b/substrate/serai/primitives/Cargo.toml @@ -18,7 +18,8 @@ scale-info = { version = "2", default-features = false, features = ["derive"] } serde = { version = "1", features = ["derive"], optional = true } sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } [features] -std = ["scale/std", "scale-info/std", "serde", "sp-core/std"] +std = ["scale/std", "scale-info/std", "serde", "sp-core/std", "sp-runtime/std"] default = ["std"] diff --git a/substrate/serai/primitives/src/account.rs b/substrate/serai/primitives/src/account.rs new file mode 100644 index 00000000..4fcd2390 --- /dev/null +++ b/substrate/serai/primitives/src/account.rs @@ -0,0 +1,93 @@ +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use sp_core::sr25519::{Public, Signature as RistrettoSignature}; +#[cfg(feature = "std")] +use sp_core::{Pair as PairTrait, sr25519::Pair}; + +use sp_runtime::traits::{LookupError, Lookup, StaticLookup}; + +pub type PublicKey = Public; + +#[derive( + Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct SeraiAddress(pub [u8; 32]); +impl SeraiAddress { + pub fn new(key: [u8; 32]) -> SeraiAddress { + SeraiAddress(key) + } +} + +impl From<[u8; 32]> for SeraiAddress { + fn from(key: [u8; 32]) -> SeraiAddress { + SeraiAddress(key) + } +} + +impl From for SeraiAddress { + fn from(key: PublicKey) -> SeraiAddress { + SeraiAddress(key.0) + } +} + +impl From for PublicKey { + fn from(address: SeraiAddress) -> PublicKey { + PublicKey::from_raw(address.0) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for SeraiAddress { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // TODO: Bech32 + write!(f, "{:?}", self.0) + } +} + +#[cfg(feature = "std")] +pub fn insecure_pair_from_name(name: &'static str) -> Pair { + Pair::from_string(&format!("//{name}"), None).unwrap() +} + +pub struct AccountLookup; +impl Lookup for AccountLookup { + type Source = SeraiAddress; + type Target = PublicKey; + fn lookup(&self, source: SeraiAddress) -> Result { + Ok(PublicKey::from_raw(source.0)) + } +} +impl StaticLookup for AccountLookup { + type Source = SeraiAddress; + type Target = PublicKey; + fn lookup(source: SeraiAddress) -> Result { + Ok(source.into()) + } + fn unlookup(source: PublicKey) -> SeraiAddress { + source.into() + } +} + +pub type Signature = RistrettoSignature; + +pub const fn pallet_address(pallet: &'static [u8]) -> SeraiAddress { + let mut address = [0; 32]; + let mut set = false; + // Implement a while loop since we can't use a for loop + let mut i = 0; + while i < pallet.len() { + address[i] = pallet[i]; + if address[i] != 0 { + set = true; + } + i += 1; + } + // Make sure this address isn't the identity point + // Doesn't do address != [0; 32] since that's not const + assert!(set, "address is the identity point"); + SeraiAddress(address) +} diff --git a/substrate/serai/primitives/src/amount.rs b/substrate/serai/primitives/src/amount.rs index daf40abe..5d1875c5 100644 --- a/substrate/serai/primitives/src/amount.rs +++ b/substrate/serai/primitives/src/amount.rs @@ -1,20 +1,25 @@ -use core::ops::{Add, Sub, Mul}; +use core::{ + ops::{Add, Sub, Mul}, + fmt::Debug, +}; use scale::{Encode, Decode, MaxEncodedLen}; use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; +/// The type used for amounts within Substrate. +// Distinct from Amount due to Substrate's requirements on this type. +// While Amount could have all the necessary traits implemented, not only are they many, it'd make +// Amount a large type with a variety of misc functions. +// The current type's minimalism sets clear bounds on usage. +pub type SubstrateAmount = u64; /// The type used for amounts. #[derive( Clone, Copy, PartialEq, Eq, PartialOrd, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, )] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct Amount(pub u64); - -/// One whole coin with eight decimals. -#[allow(clippy::inconsistent_digit_grouping)] -pub const COIN: Amount = Amount(1_000_000_00); +pub struct Amount(pub SubstrateAmount); impl Add for Amount { type Output = Amount; @@ -37,3 +42,12 @@ impl Mul for Amount { Amount(self.0.checked_mul(other.0).unwrap()) } } + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct WithAmount< + T: Clone + PartialEq + Eq + Debug + Encode + Decode + MaxEncodedLen + TypeInfo, +> { + pub data: T, + pub amount: Amount, +} diff --git a/substrate/serai/primitives/src/balance.rs b/substrate/serai/primitives/src/balance.rs new file mode 100644 index 00000000..7842a213 --- /dev/null +++ b/substrate/serai/primitives/src/balance.rs @@ -0,0 +1,37 @@ +use core::ops::{Add, Sub, Mul}; + +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use crate::{Coin, Amount}; + +/// The type used for balances (a Coin and Balance). +#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Balance { + pub coin: Coin, + pub amount: Amount, +} + +impl Add for Balance { + type Output = Balance; + fn add(self, other: Amount) -> Balance { + Balance { coin: self.coin, amount: self.amount + other } + } +} + +impl Sub for Balance { + type Output = Balance; + fn sub(self, other: Amount) -> Balance { + Balance { coin: self.coin, amount: self.amount - other } + } +} + +impl Mul for Balance { + type Output = Balance; + fn mul(self, other: Amount) -> Balance { + Balance { coin: self.coin, amount: self.amount * other } + } +} diff --git a/substrate/serai/primitives/src/block.rs b/substrate/serai/primitives/src/block.rs new file mode 100644 index 00000000..a31b8a3d --- /dev/null +++ b/substrate/serai/primitives/src/block.rs @@ -0,0 +1,46 @@ +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use sp_core::H256; + +/// The type used to identify block numbers. +// Doesn't re-export tendermint-machine's due to traits. +#[derive( + Clone, Copy, Default, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct BlockNumber(pub u32); +impl From for BlockNumber { + fn from(number: u32) -> BlockNumber { + BlockNumber(number) + } +} + +/// The type used to identify block hashes. +// This may not be universally compatible +// If a block exists with a hash which isn't 32-bytes, it can be hashed into a value with 32-bytes +// This would require the processor to maintain a mapping of 32-byte IDs to actual hashes, which +// would be fine +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct BlockHash(pub [u8; 32]); + +impl AsRef<[u8]> for BlockHash { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl From<[u8; 32]> for BlockHash { + fn from(hash: [u8; 32]) -> BlockHash { + BlockHash(hash) + } +} + +impl From for BlockHash { + fn from(hash: H256) -> BlockHash { + BlockHash(hash.into()) + } +} diff --git a/substrate/serai/primitives/src/lib.rs b/substrate/serai/primitives/src/lib.rs index 2d4dc14b..b77dd249 100644 --- a/substrate/serai/primitives/src/lib.rs +++ b/substrate/serai/primitives/src/lib.rs @@ -7,57 +7,75 @@ use scale_info::TypeInfo; #[cfg(feature = "std")] use serde::{Serialize, Deserialize}; -use sp_core::{ - H256, - sr25519::{Public, Signature as RistrettoSignature}, -}; +use sp_core::{ConstU32, bounded::BoundedVec}; mod amount; pub use amount::*; +mod block; +pub use block::*; + mod coins; pub use coins::*; -pub type PublicKey = Public; -pub type SeraiAddress = PublicKey; -pub type Signature = RistrettoSignature; +mod balance; +pub use balance::*; -/// The type used to identify block numbers. -// Doesn't re-export tendermint-machine's due to traits. -#[derive( - Clone, Copy, Default, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +mod account; +pub use account::*; + +// Monero, our current longest address candidate, has a longest address of featured with payment ID +// 1 (enum) + 1 (flags) + 64 (two keys) + 8 (payment ID) = 74 +pub const MAX_ADDRESS_LEN: u32 = 74; + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct BlockNumber(pub u32); -impl From for BlockNumber { - fn from(number: u32) -> BlockNumber { - BlockNumber(number) +pub struct ExternalAddress(BoundedVec>); +impl ExternalAddress { + #[cfg(feature = "std")] + pub fn new(address: Vec) -> Result { + Ok(ExternalAddress(address.try_into().map_err(|_| "address length exceeds {MAX_ADDRESS_LEN}")?)) + } + + pub fn address(&self) -> &[u8] { + self.0.as_ref() + } + + #[cfg(feature = "std")] + pub fn consume(self) -> Vec { + self.0.into_inner() } } -/// The type used to identify block hashes. -// This may not be universally compatible -// If a block exists with a hash which isn't 32-bytes, it can be hashed into a value with 32-bytes -// This would require the processor to maintain a mapping of 32-byte IDs to actual hashes, which -// would be fine -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] -pub struct BlockHash(pub [u8; 32]); - -impl AsRef<[u8]> for BlockHash { +impl AsRef<[u8]> for ExternalAddress { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } -impl From<[u8; 32]> for BlockHash { - fn from(hash: [u8; 32]) -> BlockHash { - BlockHash(hash) +// Should be enough for a Uniswap v3 call +pub const MAX_DATA_LEN: u32 = 512; +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Data(BoundedVec>); +impl Data { + #[cfg(feature = "std")] + pub fn new(data: Vec) -> Result { + Ok(Data(data.try_into().map_err(|_| "data length exceeds {MAX_DATA_LEN}")?)) + } + + pub fn data(&self) -> &[u8] { + self.0.as_ref() + } + + #[cfg(feature = "std")] + pub fn consume(self) -> Vec { + self.0.into_inner() } } -impl From for BlockHash { - fn from(hash: H256) -> BlockHash { - BlockHash(hash.into()) +impl AsRef<[u8]> for Data { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() } } diff --git a/substrate/tokens/pallet/Cargo.toml b/substrate/tokens/pallet/Cargo.toml new file mode 100644 index 00000000..4f7bb8b7 --- /dev/null +++ b/substrate/tokens/pallet/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "tokens-pallet" +version = "0.1.0" +description = "Mint and burn Serai tokens" +license = "AGPL-3.0-only" +authors = ["Luke Parker "] +edition = "2021" +publish = false + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } + +frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false } +frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } + +pallet-assets = { git = "https://github.com/serai-dex/substrate", default-features = false } + +serai-primitives = { path = "../../serai/primitives", default-features = false } +tokens-primitives = { path = "../primitives", default-features = false } + +[features] +std = [ + "scale/std", + "scale-info/std", + + "frame-system/std", + "frame-support/std", + + "pallet-assets/std", + + "serai-primitives/std", +] +default = ["std"] diff --git a/substrate/tokens/pallet/LICENSE b/substrate/tokens/pallet/LICENSE new file mode 100644 index 00000000..f684d027 --- /dev/null +++ b/substrate/tokens/pallet/LICENSE @@ -0,0 +1,15 @@ +AGPL-3.0-only license + +Copyright (c) 2023 Luke Parker + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License Version 3 as +published by the Free Software Foundation. + +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 Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . diff --git a/substrate/tokens/pallet/src/lib.rs b/substrate/tokens/pallet/src/lib.rs new file mode 100644 index 00000000..5d0a0845 --- /dev/null +++ b/substrate/tokens/pallet/src/lib.rs @@ -0,0 +1,83 @@ +#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +pub use tokens_primitives as primitives; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::{pallet_prelude::*, RawOrigin}; + + use pallet_assets::{Config as AssetsConfig, Pallet as AssetsPallet}; + + use serai_primitives::{SubstrateAmount, Coin, Balance, PublicKey, SeraiAddress, AccountLookup}; + use primitives::{ADDRESS, OutInstruction}; + + use super::*; + + #[pallet::config] + pub trait Config: + frame_system::Config + + AssetsConfig + { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::event] + #[pallet::generate_deposit(fn deposit_event)] + pub enum Event { + // Mint is technically redundant as the assets pallet has the exact same event already + // Providing our own definition here just helps consolidate code + Mint { address: SeraiAddress, balance: Balance }, + Burn { address: SeraiAddress, balance: Balance, instruction: OutInstruction }, + } + + #[pallet::pallet] + #[pallet::generate_store(pub(crate) trait Store)] + pub struct Pallet(PhantomData); + + impl Pallet { + fn burn_internal( + address: SeraiAddress, + balance: Balance, + instruction: OutInstruction, + ) -> DispatchResult { + AssetsPallet::::burn( + RawOrigin::Signed(ADDRESS.into()).into(), + balance.coin, + address, + balance.amount.0, + )?; + Pallet::::deposit_event(Event::Burn { address, balance, instruction }); + Ok(()) + } + + pub fn mint(address: SeraiAddress, balance: Balance) { + // TODO: Prevent minting when it'd cause an amount exceeding the bond + AssetsPallet::::mint( + RawOrigin::Signed(ADDRESS.into()).into(), + balance.coin, + address, + balance.amount.0, + ) + .unwrap(); + Pallet::::deposit_event(Event::Mint { address, balance }); + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight((0, DispatchClass::Normal))] // TODO + pub fn burn( + origin: OriginFor, + balance: Balance, + instruction: OutInstruction, + ) -> DispatchResult { + Self::burn_internal(ensure_signed(origin)?.into(), balance, instruction) + } + } +} + +pub use pallet::*; diff --git a/substrate/tokens/primitives/Cargo.toml b/substrate/tokens/primitives/Cargo.toml new file mode 100644 index 00000000..155376d6 --- /dev/null +++ b/substrate/tokens/primitives/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "tokens-primitives" +version = "0.1.0" +description = "Serai tokens primitives" +license = "MIT" +authors = ["Luke Parker "] +edition = "2021" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } + +serde = { version = "1", features = ["derive"], optional = true } + +serai-primitives = { path = "../../serai/primitives", default-features = false } + +[dev-dependencies] +sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } + +[features] +std = ["scale/std", "scale-info/std", "serde", "sp-runtime/std", "serai-primitives/std"] +default = ["std"] diff --git a/substrate/tokens/primitives/LICENSE b/substrate/tokens/primitives/LICENSE new file mode 100644 index 00000000..e6bff13c --- /dev/null +++ b/substrate/tokens/primitives/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Luke Parker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/substrate/tokens/primitives/src/lib.rs b/substrate/tokens/primitives/src/lib.rs new file mode 100644 index 00000000..94c62a5a --- /dev/null +++ b/substrate/tokens/primitives/src/lib.rs @@ -0,0 +1,33 @@ +#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use serai_primitives::{SeraiAddress, ExternalAddress, Data, pallet_address}; + +pub const ADDRESS: SeraiAddress = pallet_address(b"Tokens"); + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct OutInstruction { + pub address: ExternalAddress, + pub data: Option, +} + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum Destination { + Native(SeraiAddress), + External(OutInstruction), +} + +#[test] +fn address() { + use sp_runtime::traits::TrailingZeroInput; + assert_eq!(ADDRESS, SeraiAddress::decode(&mut TrailingZeroInput::new(b"Tokens")).unwrap()); +}