From a3d9b073f8286f33e2c8d7aa9c2faedd2f404feb Mon Sep 17 00:00:00 2001 From: dylanverstraete Date: Fri, 24 Mar 2023 15:27:33 +0100 Subject: [PATCH 1/4] feat: init client --- Cargo.lock | 944 +++++++++++++++++++++++-- Cargo.toml | 3 +- tfchain-client/Cargo.toml | 36 + tfchain-client/artifacts/mainnet.scale | Bin 0 -> 141140 bytes tfchain-client/src/lib.rs | 138 ++++ tfchain-client/src/runtimes/mainnet.rs | 34 + tfchain-client/src/runtimes/mod.rs | 4 + tfchain-client/src/runtimes/types.rs | 28 + 8 files changed, 1139 insertions(+), 48 deletions(-) create mode 100644 tfchain-client/Cargo.toml create mode 100644 tfchain-client/artifacts/mainnet.scale create mode 100644 tfchain-client/src/lib.rs create mode 100644 tfchain-client/src/runtimes/mainnet.rs create mode 100644 tfchain-client/src/runtimes/mod.rs create mode 100644 tfchain-client/src/runtimes/types.rs diff --git a/Cargo.lock b/Cargo.lock index c7130d4..1ec33de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -597,6 +597,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bounded-collections" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a071c348a5ef6da1d3a87166b408170b46002382b1dda83992b5c2208cefb370" +dependencies = [ + "log", + "parity-scale-codec 3.4.0", + "scale-info", + "serde", +] + [[package]] name = "bs58" version = "0.4.0" @@ -964,7 +976,7 @@ version = "0.88.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52056f6d0584484b57fa6c1a65c1fcb15f3780d8b6a758426d9e3084169b2ddd" dependencies = [ - "cranelift-entity", + "cranelift-entity 0.88.2", ] [[package]] @@ -978,7 +990,7 @@ dependencies = [ "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", - "cranelift-entity", + "cranelift-entity 0.88.2", "cranelift-isle", "gimli 0.26.2", "log", @@ -1011,6 +1023,15 @@ dependencies = [ "serde", ] +[[package]] +name = "cranelift-entity" +version = "0.92.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e39cfc857e7e539aa623e03bb6bec11f54aef3dfdef41adcfa7b594af3b54" +dependencies = [ + "serde", +] + [[package]] name = "cranelift-frontend" version = "0.88.2" @@ -1047,13 +1068,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80fc2288957a94fd342a015811479de1837850924166d1f1856d8406e6f3609b" dependencies = [ "cranelift-codegen", - "cranelift-entity", + "cranelift-entity 0.88.2", "cranelift-frontend", "itertools", "log", "smallvec", - "wasmparser", - "wasmtime-types", + "wasmparser 0.89.1", + "wasmtime-types 1.0.2", ] [[package]] @@ -1374,6 +1395,17 @@ dependencies = [ "rusticata-macros", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "derive-syn-parse" version = "0.1.5" @@ -1648,19 +1680,6 @@ dependencies = [ "syn", ] -[[package]] -name = "env_logger" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "env_logger" version = "0.10.0" @@ -1768,7 +1787,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ - "env_logger 0.10.0", + "env_logger", "log", ] @@ -2099,6 +2118,39 @@ dependencies = [ "tt-call", ] +[[package]] +name = "frame-support" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65a607f6869bc1b0294906d2dc3a9959992f9e6a4db91b262da85266f8b15e94" +dependencies = [ + "bitflags", + "frame-metadata", + "frame-support-procedural 11.0.0", + "impl-trait-for-tuples", + "k256", + "log", + "once_cell", + "parity-scale-codec 3.4.0", + "paste 1.0.12", + "scale-info", + "serde", + "smallvec", + "sp-api 14.0.0", + "sp-arithmetic 12.0.0", + "sp-core 16.0.0", + "sp-core-hashing-proc-macro 6.0.0", + "sp-inherents 14.0.0", + "sp-io 17.0.0", + "sp-runtime 18.0.0", + "sp-staking 14.0.0", + "sp-state-machine 0.22.0", + "sp-std 6.0.0", + "sp-tracing 8.0.0", + "sp-weights 14.0.0", + "tt-call", +] + [[package]] name = "frame-support-procedural" version = "4.0.0-dev" @@ -2128,6 +2180,22 @@ dependencies = [ "syn", ] +[[package]] +name = "frame-support-procedural" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a45eed853d66d7d14d7ad65a740f62c67c1b0bb8bdf3594073fe40979c1aeea3" +dependencies = [ + "Inflector", + "cfg-expr", + "derive-syn-parse", + "frame-support-procedural-tools 4.0.0", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" @@ -2152,6 +2220,19 @@ dependencies = [ "syn", ] +[[package]] +name = "frame-support-procedural-tools" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4272f469300e22c33f15502980016e876669a93080f21e0bd2da1bc7cefc87f" +dependencies = [ + "frame-support-procedural-tools-derive 4.0.0", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" @@ -2172,6 +2253,17 @@ dependencies = [ "syn", ] +[[package]] +name = "frame-support-procedural-tools-derive" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a881492b8dfdd6065d7d8537b8f79cd27aff8c501c759ac12b0295d139ff3d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "frame-system" version = "4.0.0-dev" @@ -2208,6 +2300,25 @@ dependencies = [ "sp-weights 4.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", ] +[[package]] +name = "frame-system" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4afe7a289497c4d694a9fdbfdd57ba54ef75a44e06dd67772c2afed2c66675c" +dependencies = [ + "frame-support 16.0.0", + "log", + "parity-scale-codec 3.4.0", + "scale-info", + "serde", + "sp-core 16.0.0", + "sp-io 17.0.0", + "sp-runtime 18.0.0", + "sp-std 6.0.0", + "sp-version 16.0.0", + "sp-weights 14.0.0", +] + [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" @@ -2440,8 +2551,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -2759,6 +2872,7 @@ dependencies = [ "rustls-native-certs", "tokio", "tokio-rustls", + "webpki-roots", ] [[package]] @@ -3018,7 +3132,9 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" dependencies = [ + "jsonrpsee-client-transport", "jsonrpsee-core", + "jsonrpsee-http-client", "jsonrpsee-proc-macros", "jsonrpsee-server", "jsonrpsee-types", @@ -3075,6 +3191,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-http-client" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls", + "jsonrpsee-core", + "jsonrpsee-types", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "jsonrpsee-proc-macros" version = "0.16.2" @@ -4626,7 +4761,7 @@ dependencies = [ name = "pallet-dao" version = "0.1.0" dependencies = [ - "env_logger 0.9.3", + "env_logger", "frame-benchmarking 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "frame-support 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "frame-system 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", @@ -4708,7 +4843,7 @@ dependencies = [ name = "pallet-grid-contracts" version = "0.1.0" dependencies = [ - "env_logger 0.9.3", + "env_logger", "frame-benchmarking 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "frame-support 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "frame-system 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", @@ -4899,7 +5034,7 @@ dependencies = [ name = "pallet-tfgrid" version = "0.1.0" dependencies = [ - "env_logger 0.9.3", + "env_logger", "frame-benchmarking 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "frame-support 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "frame-system 4.0.0-dev (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", @@ -6501,7 +6636,7 @@ dependencies = [ "sc-executor-common", "sp-runtime-interface 7.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "sp-wasm-interface 7.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", - "wasmtime", + "wasmtime 1.0.2", ] [[package]] @@ -7121,6 +7256,29 @@ dependencies = [ "prometheus", ] +[[package]] +name = "scale-bits" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd7aca73785181cc41f0bbe017263e682b585ca660540ba569133901d013ecf" +dependencies = [ + "parity-scale-codec 3.4.0", + "scale-info", + "serde", +] + +[[package]] +name = "scale-decode" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d823d4be477fc33321f93d08fb6c2698273d044f01362dc27573a750deb7c233" +dependencies = [ + "parity-scale-codec 3.4.0", + "scale-bits", + "scale-info", + "thiserror", +] + [[package]] name = "scale-info" version = "2.3.1" @@ -7147,6 +7305,23 @@ dependencies = [ "syn", ] +[[package]] +name = "scale-value" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a5e7810815bd295da73e4216d1dfbced3c7c7c7054d70fa5f6e4c58123fff4" +dependencies = [ + "either", + "frame-metadata", + "parity-scale-codec 3.4.0", + "scale-bits", + "scale-decode", + "scale-info", + "serde", + "thiserror", + "yap", +] + [[package]] name = "schannel" version = "0.1.21" @@ -7577,6 +7752,25 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sp-api" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2907bc9290f2a5bf2e8817b221ccc6a572b8f2fb7523266f34b048bb979568db" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec 3.4.0", + "sp-api-proc-macro 4.0.0", + "sp-core 16.0.0", + "sp-runtime 18.0.0", + "sp-state-machine 0.22.0", + "sp-std 6.0.0", + "sp-trie 16.0.0", + "sp-version 16.0.0", + "thiserror", +] + [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" @@ -7601,6 +7795,19 @@ dependencies = [ "syn", ] +[[package]] +name = "sp-api-proc-macro" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74e620b045c0a4fa640fa50623d7da6575115d8a70c54926cfd99f3f7727d323" +dependencies = [ + "blake2", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sp-application-crypto" version = "7.0.0" @@ -7627,6 +7834,20 @@ dependencies = [ "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", ] +[[package]] +name = "sp-application-crypto" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f08604ba4bd856311946722958711a08bded5c929e1227f7a697c58deb09468" +dependencies = [ + "parity-scale-codec 3.4.0", + "scale-info", + "serde", + "sp-core 16.0.0", + "sp-io 17.0.0", + "sp-std 6.0.0", +] + [[package]] name = "sp-arithmetic" version = "6.0.0" @@ -7656,6 +7877,21 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "sp-arithmetic" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7796939f2e3b68a3b9410ea17a2063b78038cd366f57fa772dd3be0798bd3412" +dependencies = [ + "integer-sqrt", + "num-traits", + "parity-scale-codec 3.4.0", + "scale-info", + "serde", + "sp-std 6.0.0", + "static_assertions", +] + [[package]] name = "sp-block-builder" version = "4.0.0-dev" @@ -7821,6 +8057,50 @@ dependencies = [ "zeroize", ] +[[package]] +name = "sp-core" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c96dc3debbe5c22ebf18f99e6a53199efe748e6e584a1902adb88cbad66ae7c" +dependencies = [ + "array-bytes", + "base58", + "bitflags", + "blake2", + "bounded-collections", + "dyn-clonable", + "ed25519-zebra", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde", + "lazy_static", + "libsecp256k1", + "log", + "merlin", + "parity-scale-codec 3.4.0", + "parking_lot 0.12.1", + "primitive-types", + "rand 0.8.5", + "regex", + "scale-info", + "schnorrkel", + "secp256k1", + "secrecy", + "serde", + "sp-core-hashing 6.0.0", + "sp-debug-derive 6.0.0", + "sp-externalities 0.17.0", + "sp-runtime-interface 13.0.0", + "sp-std 6.0.0", + "sp-storage 11.0.0", + "ss58-registry", + "substrate-bip39", + "thiserror", + "tiny-bip39 1.0.0", + "zeroize", +] + [[package]] name = "sp-core-hashing" version = "5.0.0" @@ -7849,6 +8129,21 @@ dependencies = [ "twox-hash", ] +[[package]] +name = "sp-core-hashing" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc2d1947252b7a4e403b0a260f596920443742791765ec111daa2bbf98eff25" +dependencies = [ + "blake2", + "byteorder", + "digest 0.10.6", + "sha2 0.10.6", + "sha3", + "sp-std 6.0.0", + "twox-hash", +] + [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" @@ -7871,6 +8166,18 @@ dependencies = [ "syn", ] +[[package]] +name = "sp-core-hashing-proc-macro" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5833921310f9883f2093849d3f5e9e57e9890f6b60839498b08d4c72572cc602" +dependencies = [ + "proc-macro2", + "quote", + "sp-core-hashing 6.0.0", + "syn", +] + [[package]] name = "sp-database" version = "4.0.0-dev" @@ -7901,10 +8208,21 @@ dependencies = [ ] [[package]] -name = "sp-externalities" -version = "0.13.0" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" -dependencies = [ +name = "sp-debug-derive" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fb9dc63d54de7d7bed62a505b6e0bd66c122525ea1abb348f6564717c3df2d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-externalities" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.36#cb4f2491b00af7d7817f3a54209c26b20faa1f51" +dependencies = [ "environmental", "parity-scale-codec 3.4.0", "sp-std 5.0.0 (git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.36)", @@ -7922,6 +8240,18 @@ dependencies = [ "sp-storage 7.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", ] +[[package]] +name = "sp-externalities" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57052935c9c9b070ea6b339ef0da3bf241b7e065fc37f9c551669ee83ecfc3c1" +dependencies = [ + "environmental", + "parity-scale-codec 3.4.0", + "sp-std 6.0.0", + "sp-storage 11.0.0", +] + [[package]] name = "sp-finality-grandpa" version = "4.0.0-dev" @@ -7968,6 +8298,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sp-inherents" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241a4961e0add07b0d17f6f68de812649c9c5c2832618fd5dc1b82475dbaf771" +dependencies = [ + "async-trait", + "impl-trait-for-tuples", + "parity-scale-codec 3.4.0", + "scale-info", + "sp-core 16.0.0", + "sp-runtime 18.0.0", + "sp-std 6.0.0", + "thiserror", +] + [[package]] name = "sp-io" version = "7.0.0" @@ -8020,6 +8366,32 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "sp-io" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578959f9a7e44fd2dd96e8b8bc893cea04fcd7c00a4ffbb0b91c5013899dd02b" +dependencies = [ + "bytes", + "ed25519", + "ed25519-dalek", + "futures", + "libsecp256k1", + "log", + "parity-scale-codec 3.4.0", + "secp256k1", + "sp-core 16.0.0", + "sp-externalities 0.17.0", + "sp-keystore 0.22.0", + "sp-runtime-interface 13.0.0", + "sp-state-machine 0.22.0", + "sp-std 6.0.0", + "sp-tracing 8.0.0", + "sp-trie 16.0.0", + "tracing", + "tracing-core", +] + [[package]] name = "sp-keyring" version = "7.0.0" @@ -8064,6 +8436,23 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sp-keystore" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "480dbd54b281c638209fbcfce69902b82a0a1af0e22219d46825eadced3136b6" +dependencies = [ + "async-trait", + "futures", + "merlin", + "parity-scale-codec 3.4.0", + "parking_lot 0.12.1", + "schnorrkel", + "sp-core 16.0.0", + "sp-externalities 0.17.0", + "thiserror", +] + [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" @@ -8117,6 +8506,17 @@ dependencies = [ "regex", ] +[[package]] +name = "sp-panic-handler" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4abed79c3d5b3622f65ab065676addd9923b9b122cd257df23e2757ce487c6d2" +dependencies = [ + "backtrace", + "lazy_static", + "regex", +] + [[package]] name = "sp-rpc" version = "6.0.0" @@ -8171,6 +8571,29 @@ dependencies = [ "sp-weights 4.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", ] +[[package]] +name = "sp-runtime" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ab2fd44668d3e8674e2253a43852857a47d49be7db737e98bf157e4bcebefd" +dependencies = [ + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec 3.4.0", + "paste 1.0.12", + "rand 0.8.5", + "scale-info", + "serde", + "sp-application-crypto 17.0.0", + "sp-arithmetic 12.0.0", + "sp-core 16.0.0", + "sp-io 17.0.0", + "sp-std 6.0.0", + "sp-weights 14.0.0", +] + [[package]] name = "sp-runtime-interface" version = "7.0.0" @@ -8207,6 +8630,25 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "sp-runtime-interface" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb7707246cee4967a8cc71e3ef0e82f562e8b1020606447a6a12b99c7c1b443" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec 3.4.0", + "primitive-types", + "sp-externalities 0.17.0", + "sp-runtime-interface-proc-macro 9.0.0", + "sp-std 6.0.0", + "sp-storage 11.0.0", + "sp-tracing 8.0.0", + "sp-wasm-interface 10.0.0", + "static_assertions", +] + [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" @@ -8231,6 +8673,19 @@ dependencies = [ "syn", ] +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2773c90e5765847c5e8b4a24b553d38a9ca52ded47c142cfcfb7948f42827af9" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sp-session" version = "4.0.0-dev" @@ -8269,6 +8724,19 @@ dependencies = [ "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", ] +[[package]] +name = "sp-staking" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf0d4447b73a53f8c36915b5710914ea82d303fc880e264e241046ae5baca08" +dependencies = [ + "parity-scale-codec 3.4.0", + "scale-info", + "sp-core 16.0.0", + "sp-runtime 18.0.0", + "sp-std 6.0.0", +] + [[package]] name = "sp-state-machine" version = "0.13.0" @@ -8311,6 +8779,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "sp-state-machine" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c957b8b4c252507c12674948db427c5e34fd1760ce256922f1ec5f89f781a4f" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec 3.4.0", + "parking_lot 0.12.1", + "rand 0.8.5", + "smallvec", + "sp-core 16.0.0", + "sp-externalities 0.17.0", + "sp-panic-handler 6.0.0", + "sp-std 6.0.0", + "sp-trie 16.0.0", + "thiserror", + "tracing", +] + [[package]] name = "sp-std" version = "5.0.0" @@ -8321,6 +8810,12 @@ name = "sp-std" version = "5.0.0" source = "git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38#18bb7c7c841b101c19a8d1881b893ae8e37de460" +[[package]] +name = "sp-std" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af0ee286f98455272f64ac5bb1384ff21ac029fbb669afbaf48477faff12760e" + [[package]] name = "sp-storage" version = "7.0.0" @@ -8347,6 +8842,20 @@ dependencies = [ "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", ] +[[package]] +name = "sp-storage" +version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c20cb0c562d1a159ecb2c7ca786828c81e432c535474967d2df3a484977cea4" +dependencies = [ + "impl-serde", + "parity-scale-codec 3.4.0", + "ref-cast", + "serde", + "sp-debug-derive 6.0.0", + "sp-std 6.0.0", +] + [[package]] name = "sp-timestamp" version = "4.0.0-dev" @@ -8386,6 +8895,19 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "sp-tracing" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46bd547da89a9cda69b4ce4c91a5b7e1f86915190d83cd407b715d0c6bac042" +dependencies = [ + "parity-scale-codec 3.4.0", + "sp-std 6.0.0", + "tracing", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" @@ -8457,6 +8979,30 @@ dependencies = [ "trie-root", ] +[[package]] +name = "sp-trie" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8efbe5b6d29a18fea7c2f52e0098135f2f864b31d335d5105b40a349866ba874" +dependencies = [ + "ahash 0.8.3", + "hash-db", + "hashbrown 0.12.3", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec 3.4.0", + "parking_lot 0.12.1", + "scale-info", + "schnellru", + "sp-core 16.0.0", + "sp-std 6.0.0", + "thiserror", + "tracing", + "trie-db", + "trie-root", +] + [[package]] name = "sp-version" version = "5.0.0" @@ -8491,6 +9037,24 @@ dependencies = [ "thiserror", ] +[[package]] +name = "sp-version" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01f705c5c6c6dad760355df0b870dd8e510f720ae6adde3eeba069c116248024" +dependencies = [ + "impl-serde", + "parity-scale-codec 3.4.0", + "parity-wasm", + "scale-info", + "serde", + "sp-core-hashing-proc-macro 6.0.0", + "sp-runtime 18.0.0", + "sp-std 6.0.0", + "sp-version-proc-macro 6.0.0", + "thiserror", +] + [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" @@ -8513,6 +9077,18 @@ dependencies = [ "syn", ] +[[package]] +name = "sp-version-proc-macro" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61fa10e7a0453c9eb2bfd49067585fe54d530f020e3bfa94bf0a9ce547aa5b3" +dependencies = [ + "parity-scale-codec 3.4.0", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sp-wasm-interface" version = "7.0.0" @@ -8523,7 +9099,7 @@ dependencies = [ "parity-scale-codec 3.4.0", "sp-std 5.0.0 (git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.36)", "wasmi", - "wasmtime", + "wasmtime 1.0.2", ] [[package]] @@ -8536,7 +9112,22 @@ dependencies = [ "parity-scale-codec 3.4.0", "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", "wasmi", - "wasmtime", + "wasmtime 1.0.2", +] + +[[package]] +name = "sp-wasm-interface" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbc05650b6338808892a7b04f0c56bb1f7f928bfa9ac58e0af2c1e5bef33229" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec 3.4.0", + "sp-std 6.0.0", + "wasmi", + "wasmtime 5.0.1", ] [[package]] @@ -8570,6 +9161,22 @@ dependencies = [ "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", ] +[[package]] +name = "sp-weights" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ebab7696f915aa548494aef3ca8d15217baf10458fe6edb87e60587a47de358" +dependencies = [ + "parity-scale-codec 3.4.0", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic 12.0.0", + "sp-core 16.0.0", + "sp-debug-derive 6.0.0", + "sp-std 6.0.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -8807,6 +9414,84 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "subxt" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54639dba6a113584083968b6a8f457dedae612abe1bd214762101ca29f12e332" +dependencies = [ + "base58", + "blake2", + "derivative", + "frame-metadata", + "futures", + "getrandom 0.2.8", + "hex", + "impl-serde", + "jsonrpsee", + "parity-scale-codec 3.4.0", + "parking_lot 0.12.1", + "primitive-types", + "scale-bits", + "scale-decode", + "scale-info", + "scale-value", + "serde", + "serde_json", + "sp-core 16.0.0", + "sp-core-hashing 6.0.0", + "sp-runtime 18.0.0", + "subxt-macro", + "subxt-metadata", + "thiserror", + "tracing", +] + +[[package]] +name = "subxt-codegen" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e86cb719003f1cedf2710a6e55ca4c37aba4c989bbd3b81dd1c52af9e4827e" +dependencies = [ + "darling", + "frame-metadata", + "heck", + "hex", + "jsonrpsee", + "parity-scale-codec 3.4.0", + "proc-macro-error", + "proc-macro2", + "quote", + "scale-info", + "subxt-metadata", + "syn", + "tokio", +] + +[[package]] +name = "subxt-macro" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c08de402a78c4c06c3ee3702c80e519efdcb65911348e018b6998d04404916" +dependencies = [ + "darling", + "proc-macro-error", + "subxt-codegen", + "syn", +] + +[[package]] +name = "subxt-metadata" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2593ab5f53435e6352675af4f9851342607f37785d84c7a3fb3139550d3c35f0" +dependencies = [ + "frame-metadata", + "parity-scale-codec 3.4.0", + "scale-info", + "sp-core-hashing 6.0.0", +] + [[package]] name = "syn" version = "1.0.109" @@ -8937,6 +9622,23 @@ dependencies = [ "try-runtime-cli", ] +[[package]] +name = "tfchain-client" +version = "0.1.0" +dependencies = [ + "frame-system 16.0.0", + "pallet-balances", + "parity-scale-codec 3.4.0", + "serde", + "sp-core 16.0.0", + "sp-io 7.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", + "sp-runtime 7.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", + "sp-std 5.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-v0.9.38)", + "subxt", + "subxt-codegen", + "tokio", +] + [[package]] name = "tfchain-runtime" version = "0.1.0" @@ -9889,6 +10591,16 @@ dependencies = [ "indexmap", ] +[[package]] +name = "wasmparser" +version = "0.96.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adde01ade41ab9a5d10ec8ed0bb954238cf8625b5cd5a13093d6de2ad9c2be1a" +dependencies = [ + "indexmap", + "url", +] + [[package]] name = "wasmtime" version = "1.0.2" @@ -9908,15 +10620,40 @@ dependencies = [ "rayon", "serde", "target-lexicon", - "wasmparser", + "wasmparser 0.89.1", "wasmtime-cache", "wasmtime-cranelift", - "wasmtime-environ", - "wasmtime-jit", - "wasmtime-runtime", + "wasmtime-environ 1.0.2", + "wasmtime-jit 1.0.2", + "wasmtime-runtime 1.0.2", "windows-sys 0.36.1", ] +[[package]] +name = "wasmtime" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ffcc607adc9da024e87ca814592d4bc67f5c5b58e488f5608d5734a1ebc23e" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "indexmap", + "libc", + "log", + "object 0.29.0", + "once_cell", + "paste 1.0.12", + "psm", + "serde", + "target-lexicon", + "wasmparser 0.96.0", + "wasmtime-environ 5.0.1", + "wasmtime-jit 5.0.1", + "wasmtime-runtime 5.0.1", + "windows-sys 0.42.0", +] + [[package]] name = "wasmtime-asm-macros" version = "1.0.2" @@ -9926,6 +10663,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "wasmtime-asm-macros" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cb5dc4d79cd7b2453c395f64e9013d2ad90bd083be556d5565cb224ebe8d57" +dependencies = [ + "cfg-if", +] + [[package]] name = "wasmtime-cache" version = "1.0.2" @@ -9954,7 +10700,7 @@ checksum = "4bd91339b742ff20bfed4532a27b73c86b5bcbfedd6bea2dcdf2d64471e1b5c6" dependencies = [ "anyhow", "cranelift-codegen", - "cranelift-entity", + "cranelift-entity 0.88.2", "cranelift-frontend", "cranelift-native", "cranelift-wasm", @@ -9963,8 +10709,8 @@ dependencies = [ "object 0.29.0", "target-lexicon", "thiserror", - "wasmparser", - "wasmtime-environ", + "wasmparser 0.89.1", + "wasmtime-environ 1.0.2", ] [[package]] @@ -9974,7 +10720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebb881c61f4f627b5d45c54e629724974f8a8890d455bcbe634330cc27309644" dependencies = [ "anyhow", - "cranelift-entity", + "cranelift-entity 0.88.2", "gimli 0.26.2", "indexmap", "log", @@ -9982,8 +10728,27 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasmparser", - "wasmtime-types", + "wasmparser 0.89.1", + "wasmtime-types 1.0.2", +] + +[[package]] +name = "wasmtime-environ" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9350c919553cddf14f78f9452119c8004d7ef6bfebb79a41a21819ed0c5604d8" +dependencies = [ + "anyhow", + "cranelift-entity 0.92.1", + "gimli 0.26.2", + "indexmap", + "log", + "object 0.29.0", + "serde", + "target-lexicon", + "thiserror", + "wasmparser 0.96.0", + "wasmtime-types 5.0.1", ] [[package]] @@ -10005,12 +10770,35 @@ dependencies = [ "serde", "target-lexicon", "thiserror", - "wasmtime-environ", - "wasmtime-jit-debug", - "wasmtime-runtime", + "wasmtime-environ 1.0.2", + "wasmtime-jit-debug 1.0.2", + "wasmtime-runtime 1.0.2", "windows-sys 0.36.1", ] +[[package]] +name = "wasmtime-jit" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ba5779ea786386432b94c9fc9ad5597346c319e8239db0d98d5be5cc109a7e" +dependencies = [ + "addr2line 0.17.0", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle", + "gimli 0.26.2", + "log", + "object 0.29.0", + "rustc-demangle", + "serde", + "target-lexicon", + "wasmtime-environ 5.0.1", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime 5.0.1", + "windows-sys 0.42.0", +] + [[package]] name = "wasmtime-jit-debug" version = "1.0.2" @@ -10022,6 +10810,26 @@ dependencies = [ "rustix 0.35.13", ] +[[package]] +name = "wasmtime-jit-debug" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9841a44c82c74101c10ad4f215392761a2523b3c6c838597962bdb6de75fdb3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd4356c2493002da3b111d470c2ecea65a3017009afce8adc46eaa5758739891" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.42.0", +] + [[package]] name = "wasmtime-runtime" version = "1.0.2" @@ -10041,22 +10849,58 @@ dependencies = [ "rand 0.8.5", "rustix 0.35.13", "thiserror", - "wasmtime-asm-macros", - "wasmtime-environ", - "wasmtime-jit-debug", + "wasmtime-asm-macros 1.0.2", + "wasmtime-environ 1.0.2", + "wasmtime-jit-debug 1.0.2", "windows-sys 0.36.1", ] +[[package]] +name = "wasmtime-runtime" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd26efea7a790fcf430e663ba2519f0ab6eb8980adf8b0c58c62b727da77c2ec" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "indexmap", + "libc", + "log", + "mach", + "memfd", + "memoffset 0.6.5", + "paste 1.0.12", + "rand 0.8.5", + "rustix 0.36.9", + "wasmtime-asm-macros 5.0.1", + "wasmtime-environ 5.0.1", + "wasmtime-jit-debug 5.0.1", + "windows-sys 0.42.0", +] + [[package]] name = "wasmtime-types" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d23d61cb4c46e837b431196dd06abb11731541021916d03476a178b54dc07aeb" dependencies = [ - "cranelift-entity", + "cranelift-entity 0.88.2", "serde", "thiserror", - "wasmparser", + "wasmparser 0.89.1", +] + +[[package]] +name = "wasmtime-types" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86e1e4f66a2b9a114f9def450ab9971828c968db6ea6fccd613724b771fa4913" +dependencies = [ + "cranelift-entity 0.92.1", + "serde", + "thiserror", + "wasmparser 0.96.0", ] [[package]] @@ -10616,6 +11460,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "yap" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc77f52dc9e9b10d55d3f4462c3b7fc393c4f17975d641542833ab2d3bc26ef" + [[package]] name = "yasna" version = "0.5.1" diff --git a/Cargo.toml b/Cargo.toml index 8a475e2..84532f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,8 @@ members = [ 'runtime', 'pallets/*', 'support', - 'primitives' + 'primitives', + 'tfchain-client' ] [profile.release] diff --git a/tfchain-client/Cargo.toml b/tfchain-client/Cargo.toml new file mode 100644 index 0000000..7c73240 --- /dev/null +++ b/tfchain-client/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "tfchain-client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +path = "src/lib.rs" +name = "tfchain_client" + +[dependencies] +codec = {package = "parity-scale-codec", workspace = true, features = ["derive"]} +subxt = "0.27.1" +subxt-codegen = "0.27.1" +tokio = { version = "1.8", features = ["rt-multi-thread", "macros", "time"] } +serde = { workspace = true, features = ["derive"] } + +# Substrate stuff +sp-core = { version = "16.0.0", default-features = false } +frame-system = { version = "16.0.0", default-features = false } +sp-std.workspace = true +sp-runtime.workspace = true +sp-io.workspace = true +pallet-balances.workspace = true + +[features] +default = ['std'] +std = [ + 'sp-std/std', + 'sp-runtime/std', + 'sp-io/std', + 'sp-core/std', + 'frame-system/std', + 'pallet-balances/std' +] \ No newline at end of file diff --git a/tfchain-client/artifacts/mainnet.scale b/tfchain-client/artifacts/mainnet.scale new file mode 100644 index 0000000000000000000000000000000000000000..62af7d396f63ff525c50f147761234178f379169 GIT binary patch literal 141140 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 literal 0 HcmV?d00001 diff --git a/tfchain-client/src/lib.rs b/tfchain-client/src/lib.rs new file mode 100644 index 0000000..4cbd906 --- /dev/null +++ b/tfchain-client/src/lib.rs @@ -0,0 +1,138 @@ +pub mod runtimes; +use crate::runtimes::mainnet; +use crate::runtimes::types::*; +use serde::{Deserialize, Serialize}; +use sp_core::{crypto::SecretStringError, ed25519, sr25519, Pair}; +use std::str::FromStr; +use subxt::{ + tx::{PairSigner, Signer}, + Error, OnlineClient, PolkadotConfig, +}; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Runtime { + // Local, + // Devnet, + // Testnet, + Mainnet, +} + +impl FromStr for Runtime { + type Err = &'static str; + + fn from_str(v: &str) -> Result { + match v { + // "local" => Ok(Self::Local), + // "devnet" => Ok(Self::Devnet), + "mainnet" => Ok(Self::Mainnet), + // "testnet" => Ok(Self::Testnet), + _ => Err("unknown runtime"), + } + } +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +pub enum KeyType { + Sr25519, + Ed25519, +} + +impl FromStr for KeyType { + type Err = &'static str; + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "sr25519" => Ok(Self::Sr25519), + "ed25519" => Ok(Self::Ed25519), + _ => Err("unknown key type"), + } + } +} + +#[derive(Clone)] +pub enum KeyPair { + Sr25519(sr25519::Pair), + Ed25519(ed25519::Pair), +} + +impl KeyPair { + // create a key pair from a seed prefixed with `0x`. or a BIP-39 phrase + pub fn from_phrase>( + k: KeyType, + phrase: S, + password: Option<&str>, + ) -> Result { + let phrase = phrase.as_ref(); + + let pair = match k { + KeyType::Sr25519 => { + let pair: sr25519::Pair = Pair::from_string(phrase, password)?; + Self::Sr25519(pair) + }, + KeyType::Ed25519 => { + let pair: ed25519::Pair = Pair::from_string(phrase, password)?; + Self::Ed25519(pair) + }, + }; + + Ok(pair) + } + + pub fn signer(&self) -> Box + Send + Sync> { + match self { + Self::Ed25519(pair) => Box::new(PairSigner::new(pair.clone())), + Self::Sr25519(pair) => Box::new(PairSigner::new(pair.clone())), + } + } +} + +impl From for KeyPair { + fn from(value: sr25519::Pair) -> Self { + Self::Sr25519(value) + } +} + +impl From for KeyPair { + fn from(value: ed25519::Pair) -> Self { + Self::Ed25519(value) + } +} + +#[derive(Clone)] +pub struct Client { + pub runtime: Runtime, + pub api: OnlineClient, +} + +macro_rules! call { + ($self:ident, $name:ident, $($arg:expr),+) => ( + match $self.runtime { + // Runtime::Local => local::$name($self, $($arg),+).await, + // Runtime::Devnet => devnet::$name($self, $($arg),+).await, + // Runtime::Testnet => testnet::$name($self, $($arg),+).await, + Runtime::Mainnet => mainnet::$name($self, $($arg),+).await, + } + ) +} + +impl Client { + pub async fn new>(url: U, runtime: Runtime) -> Result { + let api = OnlineClient::::from_url(url).await?; + + Ok(Client { api, runtime }) + } + + pub async fn get_balance( + &self, + account: &AccountId32, + at_block: Option, + ) -> Result, Error> { + call!(self, get_balance, account, at_block) + } + + pub async fn get_block_hash( + &self, + block_number: Option, + ) -> Result, Error> { + call!(self, get_block_hash, block_number) + } +} diff --git a/tfchain-client/src/runtimes/mainnet.rs b/tfchain-client/src/runtimes/mainnet.rs new file mode 100644 index 0000000..bb776b6 --- /dev/null +++ b/tfchain-client/src/runtimes/mainnet.rs @@ -0,0 +1,34 @@ +use super::types::*; +use crate::Client; +use subxt::{subxt, Error}; + +#[subxt(runtime_metadata_path = "artifacts/mainnet.scale")] +pub mod mainnet {} +pub use mainnet::runtime_types::frame_system::AccountInfo; + +pub type AccountData = mainnet::runtime_types::pallet_balances::AccountData; +pub type SystemAccountInfo = AccountInfo; + +use super::types::SystemAccountInfo as GenericAccountInfo; + +pub async fn get_block_hash( + cl: &Client, + block_number: Option, +) -> Result, Error> { + cl.api.rpc().block_hash(block_number).await +} + +pub async fn get_balance( + cl: &Client, + account: &AccountId32, + at_block: Option, +) -> Result, Error> { + Ok(cl + .api + .storage() + .at(at_block) + .await? + .fetch(&mainnet::storage().system().account(account)) + .await? + .map(|t| GenericAccountInfo::from(t))) +} diff --git a/tfchain-client/src/runtimes/mod.rs b/tfchain-client/src/runtimes/mod.rs new file mode 100644 index 0000000..1c60b14 --- /dev/null +++ b/tfchain-client/src/runtimes/mod.rs @@ -0,0 +1,4 @@ +#![allow(clippy::all)] + +pub mod mainnet; +pub mod types; diff --git a/tfchain-client/src/runtimes/types.rs b/tfchain-client/src/runtimes/types.rs new file mode 100644 index 0000000..c447224 --- /dev/null +++ b/tfchain-client/src/runtimes/types.rs @@ -0,0 +1,28 @@ +use subxt::{Config, PolkadotConfig}; + +pub use frame_system::AccountInfo; +pub use pallet_balances::AccountData; +pub type Hash = ::Hash; +pub type BlockNumber = subxt::rpc::types::BlockNumber; +pub use subxt::utils::AccountId32; + +pub type SystemAccountInfo = AccountInfo>; + +use super::mainnet::SystemAccountInfo as MainnetSystemAccountInfo; + +impl From for SystemAccountInfo { + fn from(info: MainnetSystemAccountInfo) -> Self { + SystemAccountInfo { + nonce: info.nonce, + consumers: info.consumers, + providers: info.providers, + sufficients: info.sufficients, + data: pallet_balances::AccountData { + free: info.data.free, + fee_frozen: info.data.fee_frozen, + misc_frozen: info.data.misc_frozen, + reserved: info.data.reserved, + }, + } + } +} From b030e516ad36f93d25aecae28f8aa92594516170 Mon Sep 17 00:00:00 2001 From: dylanverstraete Date: Fri, 24 Mar 2023 16:44:16 +0100 Subject: [PATCH 2/4] feat: add balances transfer --- tfchain-client/src/lib.rs | 30 +++++++++++++++++++++++--- tfchain-client/src/runtimes/mainnet.rs | 29 ++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/tfchain-client/src/lib.rs b/tfchain-client/src/lib.rs index 4cbd906..778592e 100644 --- a/tfchain-client/src/lib.rs +++ b/tfchain-client/src/lib.rs @@ -4,6 +4,10 @@ use crate::runtimes::types::*; use serde::{Deserialize, Serialize}; use sp_core::{crypto::SecretStringError, ed25519, sr25519, Pair}; use std::str::FromStr; +use subxt::config::extrinsic_params::BaseExtrinsicParams; +use subxt::config::polkadot::PlainTip; +use subxt::config::WithExtrinsicParams; +use subxt::SubstrateConfig; use subxt::{ tx::{PairSigner, Signer}, Error, OnlineClient, PolkadotConfig, @@ -77,14 +81,34 @@ impl KeyPair { Ok(pair) } - pub fn signer(&self) -> Box + Send + Sync> { + pub fn signer(&self) -> KeypairSigner { match self { - Self::Ed25519(pair) => Box::new(PairSigner::new(pair.clone())), - Self::Sr25519(pair) => Box::new(PairSigner::new(pair.clone())), + Self::Ed25519(pair) => KeypairSigner(Box::new(PairSigner::new(pair.clone()))), + Self::Sr25519(pair) => KeypairSigner(Box::new(PairSigner::new(pair.clone()))), } } } +pub struct KeypairSigner(Box + Send + Sync>); + +impl + subxt::tx::Signer< + WithExtrinsicParams>, + > for KeypairSigner +{ + fn account_id(&self) -> &> as subxt::Config>::AccountId{ + self.0.account_id() + } + + fn address(&self) -> > as subxt::Config>::Address{ + self.0.address() + } + + fn sign(&self, signer_payload: &[u8]) -> > as subxt::Config>::Signature{ + self.0.sign(signer_payload) + } +} + impl From for KeyPair { fn from(value: sr25519::Pair) -> Self { Self::Sr25519(value) diff --git a/tfchain-client/src/runtimes/mainnet.rs b/tfchain-client/src/runtimes/mainnet.rs index bb776b6..69d0aa7 100644 --- a/tfchain-client/src/runtimes/mainnet.rs +++ b/tfchain-client/src/runtimes/mainnet.rs @@ -1,5 +1,5 @@ use super::types::*; -use crate::Client; +use crate::{Client, KeyPair}; use subxt::{subxt, Error}; #[subxt(runtime_metadata_path = "artifacts/mainnet.scale")] @@ -32,3 +32,30 @@ pub async fn get_balance( .await? .map(|t| GenericAccountInfo::from(t))) } + +pub async fn transfer_native( + cl: &Client, + kp: &KeyPair, + dest: AccountId32, + value: u128, +) -> Result { + let transfer_tx = mainnet::tx().balances().transfer(dest.into(), value); + + let s = &kp.signer(); + + let transfer = cl + .api + .tx() + .sign_and_submit_then_watch_default(&transfer_tx, s) + .await? + .wait_for_finalized_success() + .await?; + + let balances_transfer = transfer.find_first::()?; + + if let Some(_) = balances_transfer { + Ok(transfer.block_hash()) + } else { + Err(Error::Other(String::from("failed to transfer"))) + } +} From c47af94d24a795903fe62b2bda84c7c8ba26145e Mon Sep 17 00:00:00 2001 From: dylanverstraete Date: Mon, 27 Mar 2023 10:16:56 +0200 Subject: [PATCH 3/4] fix: make it compile --- tfchain-client/src/runtimes/mainnet.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/tfchain-client/src/runtimes/mainnet.rs b/tfchain-client/src/runtimes/mainnet.rs index 69d0aa7..56fc3a7 100644 --- a/tfchain-client/src/runtimes/mainnet.rs +++ b/tfchain-client/src/runtimes/mainnet.rs @@ -2,7 +2,7 @@ use super::types::*; use crate::{Client, KeyPair}; use subxt::{subxt, Error}; -#[subxt(runtime_metadata_path = "artifacts/mainnet.scale")] +#[subxt(runtime_metadata_path = "artifacts/mainnet.scale", derive_for_all_types = "Eq, PartialEq")] pub mod mainnet {} pub use mainnet::runtime_types::frame_system::AccountInfo; @@ -33,17 +33,21 @@ pub async fn get_balance( .map(|t| GenericAccountInfo::from(t))) } +// Wrapper around the transfer function of the balances pallet +// This function will wait for the transaction to be finalized and return the block hash +// If the transaction fails, it will return an error +// If the transaction is successful, it will return the block hash pub async fn transfer_native( cl: &Client, kp: &KeyPair, dest: AccountId32, - value: u128, + amount: u128, ) -> Result { - let transfer_tx = mainnet::tx().balances().transfer(dest.into(), value); + let transfer_tx = mainnet::tx().balances().transfer(dest.clone().into(), amount); let s = &kp.signer(); - let transfer = cl + let events = cl .api .tx() .sign_and_submit_then_watch_default(&transfer_tx, s) @@ -51,10 +55,18 @@ pub async fn transfer_native( .wait_for_finalized_success() .await?; - let balances_transfer = transfer.find_first::()?; + let expected_event = mainnet::balances::events::Transfer { + from: s.0.account_id().clone(), + to: dest.into(), + amount, + }; - if let Some(_) = balances_transfer { - Ok(transfer.block_hash()) + let exists = events + .find::() + .any(|e| e.map(|x| assert_eq!(x, expected_event)).is_ok()); + + if exists { + Ok(events.block_hash()) } else { Err(Error::Other(String::from("failed to transfer"))) } From 69ca6a0f6833aa445c937f07e42563097af28498 Mon Sep 17 00:00:00 2001 From: dylanverstraete Date: Mon, 27 Mar 2023 10:26:22 +0200 Subject: [PATCH 4/4] feat: extend client --- tfchain-client/src/lib.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tfchain-client/src/lib.rs b/tfchain-client/src/lib.rs index 778592e..66643ab 100644 --- a/tfchain-client/src/lib.rs +++ b/tfchain-client/src/lib.rs @@ -159,4 +159,13 @@ impl Client { ) -> Result, Error> { call!(self, get_block_hash, block_number) } + + pub async fn transfer_native( + &self, + keypair: &KeyPair, + to: AccountId32, + amount: u128, + ) -> Result { + call!(self, transfer_native, keypair, to, amount) + } }