From a33b8f5ec6b99540ee7199a593b59d5dab127906 Mon Sep 17 00:00:00 2001 From: illuzen Date: Tue, 10 Feb 2026 19:42:38 +0800 Subject: [PATCH 01/26] new wormhole api --- Cargo.lock | 338 ++++++++++++++++++++++++++++++++++---------- Cargo.toml | 15 +- src/cli/wormhole.rs | 13 +- 3 files changed, 284 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4635d9..5df6615 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -152,9 +152,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] name = "aquamarine" @@ -880,9 +880,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" @@ -958,9 +958,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.56" +version = "4.5.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" +checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a" dependencies = [ "clap_builder", "clap_derive", @@ -968,9 +968,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.56" +version = "4.5.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" +checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238" dependencies = [ "anstream", "anstyle", @@ -2009,6 +2009,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "getrandom_or_panic" version = "0.0.3" @@ -2322,14 +2335,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -2449,6 +2461,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -2543,6 +2561,8 @@ checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] @@ -2847,11 +2867,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.180" +version = "0.2.181" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" [[package]] name = "libm" @@ -3018,9 +3044,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memory-db" @@ -3551,8 +3577,6 @@ dependencies = [ [[package]] name = "plonky2_maybe_rayon" version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1e554181dc95243b8d9948ae7bae5759c7fb2502fed28f671f95ef38079406" dependencies = [ "rayon", ] @@ -3560,8 +3584,6 @@ dependencies = [ [[package]] name = "plonky2_util" version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c32c137808ca984ab2458b612b7eb0462d853ee041a3136e83d54b96074c7610" [[package]] name = "polkavm-common" @@ -3639,9 +3661,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "potential_utf" @@ -3811,8 +3833,6 @@ dependencies = [ [[package]] name = "qp-plonky2" version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39530b02faa85964bba211e030afa2d54995b403b0022f88e984c4c65679c4bc" dependencies = [ "ahash", "anyhow", @@ -3828,7 +3848,9 @@ dependencies = [ "p3-symmetric", "plonky2_maybe_rayon", "plonky2_util", + "qp-plonky2-core", "qp-plonky2-field", + "qp-plonky2-verifier", "qp-poseidon-constants", "rand 0.8.5", "rand_chacha 0.3.1", @@ -3838,11 +3860,33 @@ dependencies = [ "web-time", ] +[[package]] +name = "qp-plonky2-core" +version = "1.0.0" +dependencies = [ + "ahash", + "anyhow", + "hashbrown 0.14.5", + "itertools 0.11.0", + "keccak-hash 0.8.0", + "log", + "num", + "p3-field", + "p3-goldilocks", + "p3-poseidon2", + "p3-symmetric", + "plonky2_util", + "qp-plonky2-field", + "qp-poseidon-constants", + "rand 0.8.5", + "serde", + "static_assertions", + "unroll", +] + [[package]] name = "qp-plonky2-field" version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8d52dadf3bb92708c309922b62d7f3f2587d3047f9fe05a0c9f587e2890526" dependencies = [ "anyhow", "itertools 0.11.0", @@ -3855,6 +3899,30 @@ dependencies = [ "unroll", ] +[[package]] +name = "qp-plonky2-verifier" +version = "2.0.0" +dependencies = [ + "ahash", + "anyhow", + "hashbrown 0.14.5", + "itertools 0.11.0", + "keccak-hash 0.8.0", + "log", + "num", + "p3-field", + "p3-goldilocks", + "p3-poseidon2", + "p3-symmetric", + "plonky2_util", + "qp-plonky2-core", + "qp-plonky2-field", + "qp-poseidon-constants", + "serde", + "static_assertions", + "unroll", +] + [[package]] name = "qp-poseidon" version = "1.0.7" @@ -3935,23 +4003,20 @@ dependencies = [ [[package]] name = "qp-wormhole-aggregator" -version = "0.1.8" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits?branch=illuzen%2Fagg-fees#67cf016f6f0237f61dab644d0724124311a15e1f" +version = "1.0.1" dependencies = [ "anyhow", + "hex", "qp-plonky2", "qp-wormhole-circuit", "qp-wormhole-prover", - "qp-wormhole-verifier", "qp-zk-circuits-common", "rayon", - "test-helpers", ] [[package]] name = "qp-wormhole-circuit" -version = "0.1.8" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits?branch=illuzen%2Fagg-fees#67cf016f6f0237f61dab644d0724124311a15e1f" +version = "1.0.1" dependencies = [ "anyhow", "hex", @@ -3959,10 +4024,16 @@ dependencies = [ "qp-zk-circuits-common", ] +[[package]] +name = "qp-wormhole-inputs" +version = "1.0.1" +dependencies = [ + "anyhow", +] + [[package]] name = "qp-wormhole-prover" -version = "0.1.8" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits?branch=illuzen%2Fagg-fees#67cf016f6f0237f61dab644d0724124311a15e1f" +version = "1.0.1" dependencies = [ "anyhow", "qp-plonky2", @@ -3972,19 +4043,16 @@ dependencies = [ [[package]] name = "qp-wormhole-verifier" -version = "0.1.8" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits?branch=illuzen%2Fagg-fees#67cf016f6f0237f61dab644d0724124311a15e1f" +version = "1.0.1" dependencies = [ "anyhow", - "qp-plonky2", - "qp-wormhole-circuit", - "qp-zk-circuits-common", + "qp-plonky2-verifier", + "qp-wormhole-inputs", ] [[package]] name = "qp-zk-circuits-common" -version = "0.1.8" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits?branch=illuzen%2Fagg-fees#67cf016f6f0237f61dab644d0724124311a15e1f" +version = "1.0.1" dependencies = [ "anyhow", "hex", @@ -4236,9 +4304,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -4248,9 +4316,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -4259,9 +4327,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "reqwest" @@ -4475,9 +4543,9 @@ checksum = "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01" [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -4973,9 +5041,9 @@ checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -5885,12 +5953,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.24.0" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.1", "once_cell", "rustix", "windows-sys 0.61.2", @@ -5907,8 +5975,7 @@ dependencies = [ [[package]] name = "test-helpers" -version = "0.1.8" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits?branch=illuzen%2Fagg-fees#67cf016f6f0237f61dab644d0724124311a15e1f" +version = "1.0.1" dependencies = [ "anyhow", "hex", @@ -5968,9 +6035,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.46" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", @@ -5989,9 +6056,9 @@ checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.26" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -6408,9 +6475,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "unicode-normalization" @@ -6603,6 +6670,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.108" @@ -6662,6 +6738,28 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser 0.244.0", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser 0.244.0", +] + [[package]] name = "wasmi" version = "0.40.0" @@ -6675,7 +6773,7 @@ dependencies = [ "wasmi_collections", "wasmi_core", "wasmi_ir", - "wasmparser", + "wasmparser 0.221.3", ] [[package]] @@ -6712,6 +6810,18 @@ dependencies = [ "bitflags 2.10.0", ] +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.10.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "web-sys" version = "0.3.85" @@ -6738,23 +6848,23 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.5", + "webpki-root-certs 1.0.6", ] [[package]] name = "webpki-root-certs" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ "rustls-pki-types", ] @@ -7094,6 +7204,88 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 2.0.114", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.114", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.10.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser 0.244.0", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.244.0", +] [[package]] name = "writeable" @@ -7153,18 +7345,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.37" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.37" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", @@ -7247,6 +7439,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1966f8ac2c1f76987d69a74d0e0f929241c10e78136434e3be70ff7f58f64214" +checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7" diff --git a/Cargo.toml b/Cargo.toml index e0c3842..279f9eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,9 +81,22 @@ qp-wormhole-prover = { git = "https://github.com/Quantus-Network/qp-zk-circuits" qp-wormhole-verifier = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-verifier", default-features = false, features = ["std"] } qp-wormhole-aggregator = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-aggregator", default-features = false, features = ["rayon", "std"] } qp-zk-circuits-common = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-zk-circuits-common", default-features = false, features = ["std"] } -qp-plonky2 = { version = "1.1.3", default-features = false } +qp-plonky2 = { version = "1.1.3", default-features = false, features = ["std", "rand"] } [dev-dependencies] tempfile = "3.8" serial_test = "3.1" qp-wormhole-test-helpers = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "test-helpers" } + +[patch."https://github.com/Quantus-Network/qp-zk-circuits"] +qp-wormhole-circuit = { path = "../qp-zk-circuits/wormhole/circuit" } +qp-wormhole-prover = { path = "../qp-zk-circuits/wormhole/prover" } +qp-wormhole-verifier = { path = "../qp-zk-circuits/wormhole/verifier" } +qp-wormhole-aggregator = { path = "../qp-zk-circuits/wormhole/aggregator" } +qp-wormhole-inputs = { path = "../qp-zk-circuits/wormhole/inputs" } +qp-zk-circuits-common = { path = "../qp-zk-circuits/common" } +test-helpers = { path = "../qp-zk-circuits/wormhole/tests/test-helpers" } + +[patch.crates-io] +qp-plonky2 = { path = "../qp-plonky2/plonky2" } +qp-plonky2-field = { path = "../qp-plonky2/field" } diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index cd6feb3..56f74f0 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -490,12 +490,8 @@ async fn aggregate_proofs( let max_leaf_proofs = validate_aggregation_params(proof_files.len(), depth, branching_factor) .map_err(crate::error::QuantusError::Generic)?; - // Build the wormhole verifier to get circuit data for parsing proofs - let config = CircuitConfig::standard_recursion_zk_config(); - let verifier = WormholeVerifier::new(config.clone(), None); - let common_data = verifier.circuit_data.common.clone(); - // Configure aggregation + let config = CircuitConfig::standard_recursion_zk_config(); let aggregation_config = TreeAggregationConfig::new(branching_factor, depth as u32); log_verbose!( @@ -505,9 +501,10 @@ async fn aggregate_proofs( max_leaf_proofs ); - // Create aggregator - let mut aggregator = - WormholeProofAggregator::new(verifier.circuit_data).with_config(aggregation_config); + // Create aggregator using circuit config + let mut aggregator = WormholeProofAggregator::from_circuit_config(config.clone()) + .with_config(aggregation_config); + let common_data = aggregator.leaf_circuit_data.common.clone(); // Load and add proofs using helper function for (idx, proof_file) in proof_files.iter().enumerate() { From 9575f352c24b7d1e384ccb358a91a438f7dc3469 Mon Sep 17 00:00:00 2001 From: illuzen Date: Wed, 11 Feb 2026 06:15:05 +0800 Subject: [PATCH 02/26] better wormhole commands --- Cargo.lock | 1 + src/cli/wormhole.rs | 628 +++++++++++++++++++++++++++++----- src/main.rs | 11 +- tests/wormhole_integration.rs | 6 +- 4 files changed, 557 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5df6615..fd20ba9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4011,6 +4011,7 @@ dependencies = [ "qp-wormhole-circuit", "qp-wormhole-prover", "qp-zk-circuits-common", + "rand 0.8.5", "rayon", ] diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 56f74f0..d8ed622 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -4,7 +4,7 @@ use crate::{ quantus_subxt::{self as quantus_node, api::wormhole}, }, cli::common::{submit_transaction, ExecutionMode}, - log_print, log_success, log_verbose, + log_error, log_print, log_success, log_verbose, wallet::QuantumKeyPair, }; use clap::Subcommand; @@ -111,6 +111,138 @@ pub fn write_proof_file(path: &str, proof_bytes: &[u8]) -> Result<(), String> { std::fs::write(path, proof_hex).map_err(|e| format!("Failed to write proof file: {}", e)) } +/// Format a balance amount from raw units (12 decimals) to human-readable format +pub fn format_balance(amount: u128) -> String { + let whole = amount / 1_000_000_000_000; + let frac = (amount % 1_000_000_000_000) / 10_000_000_000; // 2 decimal places + format!("{}.{:02} DEV", whole, frac) +} + +/// Result of checking proof verification events +pub struct VerificationResult { + pub success: bool, + pub exit_amount: Option, + pub error_message: Option, +} + +/// Check for proof verification events in a transaction +/// Returns whether ProofVerified event was found and the exit amount +async fn check_proof_verification_events( + client: &subxt::OnlineClient, + block_hash: &subxt::utils::H256, + tx_hash: &subxt::utils::H256, + verbose: bool, +) -> crate::error::Result { + use crate::chain::quantus_subxt::api::system::events::ExtrinsicFailed; + use colored::Colorize; + + let block = client.blocks().at(*block_hash).await.map_err(|e| { + crate::error::QuantusError::NetworkError(format!("Failed to get block: {e:?}")) + })?; + + let extrinsics = block.extrinsics().await.map_err(|e| { + crate::error::QuantusError::NetworkError(format!("Failed to get extrinsics: {e:?}")) + })?; + + // Find our extrinsic index + let our_extrinsic_index = extrinsics + .iter() + .enumerate() + .find(|(_, ext)| ext.hash() == *tx_hash) + .map(|(idx, _)| idx); + + let events = block.events().await.map_err(|e| { + crate::error::QuantusError::NetworkError(format!("Failed to fetch events: {e:?}")) + })?; + + let metadata = client.metadata(); + + let mut verification_result = + VerificationResult { success: false, exit_amount: None, error_message: None }; + + if verbose { + log_print!(""); + log_print!("📋 Transaction Events:"); + } + + if let Some(ext_idx) = our_extrinsic_index { + for event_result in events.iter() { + let event = event_result.map_err(|e| { + crate::error::QuantusError::NetworkError(format!("Failed to decode event: {e:?}")) + })?; + + // Only process events for our extrinsic + if let subxt::events::Phase::ApplyExtrinsic(event_ext_idx) = event.phase() { + if event_ext_idx != ext_idx as u32 { + continue; + } + + // Display event in verbose mode + if verbose { + log_print!( + " 📌 {}.{}", + event.pallet_name().bright_cyan(), + event.variant_name().bright_yellow() + ); + + // Try to decode and display event details + if let Ok(typed_event) = + event.as_root_event::() + { + log_print!(" 📝 {:?}", typed_event); + } + } + + // Check for ProofVerified event + if let Ok(Some(proof_verified)) = + event.as_event::() + { + verification_result.success = true; + verification_result.exit_amount = Some(proof_verified.exit_amount); + } + + // Check for ExtrinsicFailed event + if let Ok(Some(ExtrinsicFailed { dispatch_error, .. })) = + event.as_event::() + { + let error_msg = format_dispatch_error(&dispatch_error, &metadata); + verification_result.success = false; + verification_result.error_message = Some(error_msg); + } + } + } + } + + if verbose { + log_print!(""); + } + + Ok(verification_result) +} + +/// Format dispatch error for display +fn format_dispatch_error( + error: &crate::chain::quantus_subxt::api::runtime_types::sp_runtime::DispatchError, + metadata: &subxt::Metadata, +) -> String { + use crate::chain::quantus_subxt::api::runtime_types::sp_runtime::DispatchError; + + match error { + DispatchError::Module(module_error) => { + let pallet_name = metadata + .pallet_by_index(module_error.index) + .map(|p| p.name()) + .unwrap_or("Unknown"); + let error_index = module_error.error[0]; + format!("{}::Error[{}]", pallet_name, error_index) + }, + DispatchError::BadOrigin => "BadOrigin".to_string(), + DispatchError::CannotLookup => "CannotLookup".to_string(), + DispatchError::Other => "Other".to_string(), + _ => format!("{:?}", error), + } +} + /// Validate aggregation parameters pub fn validate_aggregation_params( num_proofs: usize, @@ -144,20 +276,16 @@ pub fn validate_aggregation_params( #[derive(Subcommand, Debug)] pub enum WormholeCommands { - /// Generate a wormhole proof - Generate { - /// Secret (32-byte hex string) + /// Submit a wormhole transfer to an unspendable account + Transfer { + /// Secret (32-byte hex string) - used to derive the unspendable account #[arg(long)] secret: String, - /// Funding amount to transfer + /// Amount to transfer #[arg(long)] amount: u128, - /// Exit account (where funds will be withdrawn) - #[arg(long)] - exit_account: String, - /// Wallet name to fund from #[arg(short, long)] from: String, @@ -169,6 +297,32 @@ pub enum WormholeCommands { /// Read password from file #[arg(long)] password_file: Option, + }, + /// Generate a wormhole proof from an existing transfer + Generate { + /// Secret (32-byte hex string) used for the transfer + #[arg(long)] + secret: String, + + /// Funding amount that was transferred + #[arg(long)] + amount: u128, + + /// Exit account (where funds will be withdrawn, hex or SS58) + #[arg(long)] + exit_account: String, + + /// Block hash to generate proof against (hex) + #[arg(long)] + block: String, + + /// Transfer count from the transfer event + #[arg(long)] + transfer_count: u64, + + /// Funding account (sender of transfer, hex or SS58) + #[arg(long)] + funding_account: String, /// Output file for the proof (default: proof.hex) #[arg(short, long, default_value = "proof.hex")] @@ -190,8 +344,9 @@ pub enum WormholeCommands { #[arg(short, long, default_value = "aggregated_proof.hex")] output: String, - /// Tree depth for aggregation (default: 1) - #[arg(long, default_value = "1")] + /// Tree depth for aggregation (default: 3, supports up to 8 proofs with + /// branching_factor=2) + #[arg(long, default_value = "3")] depth: usize, /// Branching factor for aggregation tree (default: 2) @@ -204,6 +359,16 @@ pub enum WormholeCommands { #[arg(short, long, default_value = "aggregated_proof.hex")] proof: String, }, + /// Parse and display the contents of a proof file (for debugging) + ParseProof { + /// Path to the proof file (hex-encoded) + #[arg(short, long)] + proof: String, + + /// Parse as aggregated proof (default: false, parses as leaf proof) + #[arg(long)] + aggregated: bool, + }, } pub async fn handle_wormhole_command( @@ -211,22 +376,24 @@ pub async fn handle_wormhole_command( node_url: &str, ) -> crate::error::Result<()> { match command { + WormholeCommands::Transfer { secret, amount, from, password, password_file } => + submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await, WormholeCommands::Generate { secret, amount, exit_account, - from, - password, - password_file, + block, + transfer_count, + funding_account, output, } => generate_proof( secret, amount, exit_account, - from, - password, - password_file, + block, + transfer_count, + funding_account, output, node_url, ) @@ -236,35 +403,31 @@ pub async fn handle_wormhole_command( aggregate_proofs(proofs, output, depth, branching_factor).await, WormholeCommands::VerifyAggregated { proof } => verify_aggregated_proof(proof, node_url).await, + WormholeCommands::ParseProof { proof, aggregated } => + parse_proof_file(proof, aggregated).await, } } pub type TransferProofKey = (u32, u64, AccountId32, AccountId32, u128); -async fn generate_proof( +/// Submit a wormhole transfer to an unspendable account +async fn submit_wormhole_transfer( secret_hex: String, funding_amount: u128, - exit_account_str: String, from_wallet: String, password: Option, password_file: Option, - output_file: String, node_url: &str, ) -> crate::error::Result<()> { - log_print!("Generating wormhole proof..."); + log_print!("Submitting wormhole transfer..."); - // Parse secret using helper function + // Parse secret let secret_array = parse_secret_hex(&secret_hex).map_err(crate::error::QuantusError::Generic)?; let secret: BytesDigest = secret_array.try_into().map_err(|e| { crate::error::QuantusError::Generic(format!("Failed to convert secret: {:?}", e)) })?; - // Parse exit account using helper function - let exit_account_bytes = - parse_exit_account(&exit_account_str).map_err(crate::error::QuantusError::Generic)?; - let exit_account_id = SubxtAccountId(exit_account_bytes); - // Load keypair let keypair = crate::wallet::load_keypair_from_wallet(&from_wallet, password, password_file)?; @@ -274,11 +437,9 @@ async fn generate_proof( .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to connect: {}", e)))?; let client = quantus_client.client(); - log_verbose!("Connected to node"); - let funding_account = AccountId32::new(PoseidonHasher::hash(keypair.public_key.as_ref()).0); - // Generate unspendable account + // Generate unspendable account from secret let unspendable_account = qp_wormhole_circuit::unspendable_account::UnspendableAccount::from_secret(secret) .account_id; @@ -290,17 +451,15 @@ async fn generate_proof( .expect("BytesDigest is always 32 bytes"); let unspendable_account_id = SubxtAccountId(unspendable_account_bytes); - log_verbose!("Unspendable account: {:?}", &unspendable_account_id); - log_verbose!("Exit account: {:?}", &exit_account_id); + log_verbose!("Funding account: 0x{}", hex::encode(funding_account.as_ref() as &[u8])); + log_verbose!("Unspendable account: 0x{}", hex::encode(unspendable_account_bytes)); - // Transfer to unspendable account using wormhole pallet + // Transfer to unspendable account let transfer_tx = quantus_node::api::tx().wormhole().transfer_native( subxt::ext::subxt_core::utils::MultiAddress::Id(unspendable_account_id.clone()), funding_amount, ); - log_verbose!("Submitting transfer to unspendable account..."); - let quantum_keypair = QuantumKeyPair { public_key: keypair.public_key.clone(), private_key: keypair.private_key.clone(), @@ -316,67 +475,149 @@ async fn generate_proof( .await .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; + // Get block and event details let blocks = at_best_block(&quantus_client) .await .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; let block_hash = blocks.hash(); - log_success!("Transfer included in block: {:?}", block_hash); - let events_api = client .events() .at(block_hash) .await .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; + // Find our specific transfer event let event = events_api .find::() - .next() + .find(|e| if let Ok(evt) = e { evt.to.0 == unspendable_account_bytes } else { false }) .ok_or_else(|| { - crate::error::QuantusError::Generic("No NativeTransferred event found".to_string()) + crate::error::QuantusError::Generic( + "No matching NativeTransferred event found".to_string(), + ) })? .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - log_verbose!( - "Transfer event: amount={}, transfer_count={}", - event.amount, - event.transfer_count - ); + // Output all the details needed for proof generation + log_success!("Transfer successful!"); + log_success!("Block: {:?}", block_hash); + log_print!(""); + log_print!("Use these values for proof generation:"); + log_print!(" --secret {}", secret_hex); + log_print!(" --amount {}", funding_amount); + log_print!(" --block 0x{}", hex::encode(block_hash.as_ref())); + log_print!(" --transfer-count {}", event.transfer_count); + log_print!(" --funding-account 0x{}", hex::encode(funding_account.as_ref() as &[u8])); - // Get storage proof - let storage_api = client.storage().at(block_hash); + Ok(()) +} - // Convert subxt AccountId32 to sp_core AccountId32 for hash_storage - let from_account = AccountId32::new(event.from.0); - let to_account = AccountId32::new(event.to.0); +/// Generate a wormhole proof from an existing transfer +async fn generate_proof( + secret_hex: String, + funding_amount: u128, + exit_account_str: String, + block_hash_str: String, + transfer_count: u64, + funding_account_str: String, + output_file: String, + node_url: &str, +) -> crate::error::Result<()> { + log_print!("Generating proof from existing transfer..."); + + // Parse secret + let secret_array = + parse_secret_hex(&secret_hex).map_err(crate::error::QuantusError::Generic)?; + let secret: BytesDigest = secret_array.try_into().map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to convert secret: {:?}", e)) + })?; + // Parse exit account + let exit_account_bytes = + parse_exit_account(&exit_account_str).map_err(crate::error::QuantusError::Generic)?; + let exit_account_id = SubxtAccountId(exit_account_bytes); + + // Parse funding account + let funding_account_bytes = + parse_exit_account(&funding_account_str).map_err(crate::error::QuantusError::Generic)?; + let funding_account = AccountId32::new(funding_account_bytes); + + // Parse block hash + let hash_bytes = hex::decode(block_hash_str.trim_start_matches("0x")) + .map_err(|e| crate::error::QuantusError::Generic(format!("Invalid block hash: {}", e)))?; + if hash_bytes.len() != 32 { + return Err(crate::error::QuantusError::Generic(format!( + "Block hash must be 32 bytes, got {}", + hash_bytes.len() + ))); + } + let hash: [u8; 32] = hash_bytes.try_into().unwrap(); + let block_hash = subxt::utils::H256::from(hash); + + // Connect to node + let quantus_client = QuantusClient::new(node_url) + .await + .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to connect: {}", e)))?; + let client = quantus_client.client(); + + log_verbose!("Connected to node, using block: {:?}", block_hash); + + // Generate unspendable account from secret + let unspendable_account = + qp_wormhole_circuit::unspendable_account::UnspendableAccount::from_secret(secret) + .account_id; + let unspendable_account_bytes_digest = + qp_zk_circuits_common::utils::digest_felts_to_bytes(unspendable_account); + let unspendable_account_bytes: [u8; 32] = unspendable_account_bytes_digest + .as_ref() + .try_into() + .expect("BytesDigest is always 32 bytes"); + + let from_account = funding_account.clone(); + let to_account = AccountId32::new(unspendable_account_bytes); + + // Get block + let blocks = + client.blocks().at(block_hash).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) + })?; + + // Build storage key let leaf_hash = qp_poseidon::PoseidonHasher::hash_storage::( &( NATIVE_ASSET_ID, - event.transfer_count, + transfer_count, from_account.clone(), to_account.clone(), - event.amount, + funding_amount, ) .encode(), ); + let proof_address = quantus_node::api::storage().wormhole().transfer_proof(( NATIVE_ASSET_ID, - event.transfer_count, - event.from.clone(), - event.to.clone(), - event.amount, + transfer_count, + SubxtAccountId(from_account.clone().into()), + SubxtAccountId(to_account.clone().into()), + funding_amount, )); + let mut final_key = proof_address.to_root_bytes(); final_key.extend_from_slice(&leaf_hash); + + // Verify storage key exists + let storage_api = client.storage().at(block_hash); let val = storage_api .fetch_raw(final_key.clone()) .await .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; if val.is_none() { - return Err(crate::error::QuantusError::Generic("Storage key not found".to_string())); + return Err(crate::error::QuantusError::Generic( + "Storage key not found - transfer may not exist in this block".to_string(), + )); } + // Get storage proof let proof_params = rpc_params![vec![to_hex(&final_key)], block_hash]; let read_proof: ReadProof = quantus_client .rpc_client() @@ -385,7 +626,6 @@ async fn generate_proof( .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; let header = blocks.header(); - let state_root = BytesDigest::try_from(header.state_root.as_bytes()) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; let parent_hash = BytesDigest::try_from(header.parent_hash.as_bytes()) @@ -396,7 +636,6 @@ async fn generate_proof( header.digest.encode().try_into().map_err(|_| { crate::error::QuantusError::Generic("Failed to encode digest".to_string()) })?; - let block_number = header.number; // Prepare storage proof @@ -407,17 +646,15 @@ async fn generate_proof( ) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - // Quantize the funding amount using helper function + // Quantize amounts let input_amount_quantized: u32 = quantize_funding_amount(funding_amount).map_err(crate::error::QuantusError::Generic)?; - - // Calculate output amount after fee deduction let output_amount_quantized = compute_output_amount(input_amount_quantized, VOLUME_FEE_BPS); let inputs = CircuitInputs { private: PrivateCircuitInputs { secret, - transfer_count: event.transfer_count, + transfer_count, funding_account: BytesDigest::try_from(funding_account.as_ref() as &[u8]) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, storage_proof: processed_storage_proof, @@ -430,7 +667,7 @@ async fn generate_proof( public: PublicCircuitInputs { output_amount: output_amount_quantized, volume_fee_bps: VOLUME_FEE_BPS, - nullifier: Nullifier::from_preimage(secret, event.transfer_count).hash.into(), + nullifier: Nullifier::from_preimage(secret, transfer_count).hash.into(), exit_account: BytesDigest::try_from(exit_account_id.as_ref() as &[u8]) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, block_hash: BytesDigest::try_from(block_hash.as_ref()) @@ -442,8 +679,13 @@ async fn generate_proof( }; log_verbose!("Generating ZK proof..."); - let config = CircuitConfig::standard_recursion_zk_config(); - let prover = WormholeProver::new(config); + // Load prover from pre-built bins to ensure circuit digest matches on-chain verifier + let bins_dir = std::path::Path::new("generated-bins"); + let prover = + WormholeProver::new_from_files(&bins_dir.join("prover.bin"), &bins_dir.join("common.bin")) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load prover: {}", e)) + })?; let prover_next = prover .commit(&inputs) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; @@ -461,6 +703,7 @@ async fn generate_proof( log_success!("Proof generated successfully!"); log_success!("Output: {}", output_file); + log_success!("Block: {:?}", block_hash); log_verbose!("Public inputs: {:?}", public_inputs); Ok(()) @@ -484,6 +727,8 @@ async fn aggregate_proofs( aggregator::WormholeProofAggregator, circuits::tree::TreeAggregationConfig, }; + use std::path::Path; + log_print!("Aggregating {} proofs...", proof_files.len()); // Validate aggregation parameters using helper function @@ -491,7 +736,6 @@ async fn aggregate_proofs( .map_err(crate::error::QuantusError::Generic)?; // Configure aggregation - let config = CircuitConfig::standard_recursion_zk_config(); let aggregation_config = TreeAggregationConfig::new(branching_factor, depth as u32); log_verbose!( @@ -501,9 +745,20 @@ async fn aggregate_proofs( max_leaf_proofs ); - // Create aggregator using circuit config - let mut aggregator = WormholeProofAggregator::from_circuit_config(config.clone()) - .with_config(aggregation_config); + // Load aggregator from pre-built bins to ensure circuit digest matches on-chain verifier + let bins_dir = Path::new("generated-bins"); + let mut aggregator = WormholeProofAggregator::from_prebuilt_with_paths( + &bins_dir.join("prover.bin"), + &bins_dir.join("common.bin"), + &bins_dir.join("verifier.bin"), + ) + .map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to load aggregator from pre-built bins: {}", + e + )) + })? + .with_config(aggregation_config); let common_data = aggregator.leaf_circuit_data.common.clone(); // Load and add proofs using helper function @@ -610,21 +865,67 @@ async fn verify_aggregated_proof(proof_file: String, node_url: &str) -> crate::e .await .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to submit tx: {}", e)))?; - // Wait for transaction inclusion + // Wait for transaction inclusion and verify events while let Some(Ok(status)) = tx_progress.next().await { log_verbose!("Transaction status: {:?}", status); match status { TxStatus::InBestBlock(tx_in_block) => { let block_hash = tx_in_block.block_hash(); - log_success!("Aggregated proof verified successfully on-chain!"); - log_verbose!("Included in block: {:?}", block_hash); - return Ok(()); + let tx_hash = tx_in_block.extrinsic_hash(); + + // Check for ProofVerified event + let result = check_proof_verification_events( + quantus_client.client(), + &block_hash, + &tx_hash, + crate::log::is_verbose(), + ) + .await?; + + if result.success { + log_success!("Aggregated proof verified successfully on-chain!"); + if let Some(amount) = result.exit_amount { + log_success!("Total exit amount: {}", format_balance(amount)); + } + log_verbose!("Included in block: {:?}", block_hash); + return Ok(()); + } else { + let error_msg = result.error_message.unwrap_or_else(|| { + "Aggregated proof verification failed - no ProofVerified event found" + .to_string() + }); + log_error!("❌ {}", error_msg); + return Err(crate::error::QuantusError::Generic(error_msg)); + } }, TxStatus::InFinalizedBlock(tx_in_block) => { let block_hash = tx_in_block.block_hash(); - log_success!("Aggregated proof verified successfully on-chain!"); - log_verbose!("Finalized in block: {:?}", block_hash); - return Ok(()); + let tx_hash = tx_in_block.extrinsic_hash(); + + // Check for ProofVerified event + let result = check_proof_verification_events( + quantus_client.client(), + &block_hash, + &tx_hash, + crate::log::is_verbose(), + ) + .await?; + + if result.success { + log_success!("Aggregated proof verified successfully on-chain!"); + if let Some(amount) = result.exit_amount { + log_success!("Total exit amount: {}", format_balance(amount)); + } + log_verbose!("Finalized in block: {:?}", block_hash); + return Ok(()); + } else { + let error_msg = result.error_message.unwrap_or_else(|| { + "Aggregated proof verification failed - no ProofVerified event found" + .to_string() + }); + log_error!("❌ {}", error_msg); + return Err(crate::error::QuantusError::Generic(error_msg)); + } }, TxStatus::Error { message } | TxStatus::Invalid { message } => { return Err(crate::error::QuantusError::Generic(format!( @@ -676,21 +977,65 @@ async fn verify_proof(proof_file: String, node_url: &str) -> crate::error::Resul .await .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to submit tx: {}", e)))?; - // Wait for transaction inclusion + // Wait for transaction inclusion and verify events while let Some(Ok(status)) = tx_progress.next().await { log_verbose!("Transaction status: {:?}", status); match status { TxStatus::InBestBlock(tx_in_block) => { let block_hash = tx_in_block.block_hash(); - log_success!("Proof verified successfully on-chain!"); - log_verbose!("Included in block: {:?}", block_hash); - return Ok(()); + let tx_hash = tx_in_block.extrinsic_hash(); + + // Check for ProofVerified event + let result = check_proof_verification_events( + quantus_client.client(), + &block_hash, + &tx_hash, + crate::log::is_verbose(), + ) + .await?; + + if result.success { + log_success!("Proof verified successfully on-chain!"); + if let Some(amount) = result.exit_amount { + log_success!("Exit amount: {}", format_balance(amount)); + } + log_verbose!("Included in block: {:?}", block_hash); + return Ok(()); + } else { + let error_msg = result.error_message.unwrap_or_else(|| { + "Proof verification failed - no ProofVerified event found".to_string() + }); + log_error!("❌ {}", error_msg); + return Err(crate::error::QuantusError::Generic(error_msg)); + } }, TxStatus::InFinalizedBlock(tx_in_block) => { let block_hash = tx_in_block.block_hash(); - log_success!("Proof verified successfully on-chain!"); - log_verbose!("Finalized in block: {:?}", block_hash); - return Ok(()); + let tx_hash = tx_in_block.extrinsic_hash(); + + // Check for ProofVerified event + let result = check_proof_verification_events( + quantus_client.client(), + &block_hash, + &tx_hash, + crate::log::is_verbose(), + ) + .await?; + + if result.success { + log_success!("Proof verified successfully on-chain!"); + if let Some(amount) = result.exit_amount { + log_success!("Exit amount: {}", format_balance(amount)); + } + log_verbose!("Finalized in block: {:?}", block_hash); + return Ok(()); + } else { + let error_msg = result.error_message.unwrap_or_else(|| { + "Proof verification failed - no ProofVerified event found".to_string() + }); + log_error!("❌ {}", error_msg); + return Err(crate::error::QuantusError::Generic(error_msg)); + } }, TxStatus::Error { message } | TxStatus::Invalid { message } => { return Err(crate::error::QuantusError::Generic(format!( @@ -1183,3 +1528,120 @@ mod tests { assert_eq!(VOLUME_FEE_BPS, 10); } } + +/// Parse and display the contents of a proof file for debugging +async fn parse_proof_file(proof_file: String, aggregated: bool) -> crate::error::Result<()> { + use qp_wormhole_aggregator::aggregator::WormholeProofAggregator; + use std::path::Path; + + log_print!("Parsing proof file: {}", proof_file); + + // Read proof bytes + let proof_bytes = read_proof_file(&proof_file) + .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to read proof: {}", e)))?; + + log_print!("Proof size: {} bytes", proof_bytes.len()); + + if aggregated { + use plonky2::{ + plonk::circuit_data::CommonCircuitData, util::serialization::DefaultGateSerializer, + }; + + // Load aggregated circuit common data + let bins_dir = Path::new("generated-bins"); + let common_bytes = std::fs::read(bins_dir.join("aggregated_common.bin")).map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to read aggregated_common.bin: {}", + e + )) + })?; + + let gate_serializer = DefaultGateSerializer; + let common_data = CommonCircuitData::::from_bytes(common_bytes, &gate_serializer) + .map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to deserialize aggregated common data: {:?}", + e + )) + })?; + + let proof = ProofWithPublicInputs::::from_bytes(proof_bytes.clone(), &common_data) + .map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to deserialize aggregated proof: {:?}", + e + )) + })?; + + log_print!("\nPublic inputs count: {}", proof.public_inputs.len()); + log_print!("\nPublic inputs (raw field elements):"); + for (i, pi) in proof.public_inputs.iter().enumerate() { + use plonky2::field::types::PrimeField64; + log_print!(" [{}] = {}", i, pi.to_canonical_u64()); + } + + // Try to parse as aggregated + match AggregatedPublicCircuitInputs::try_from_slice(&proof.public_inputs) { + Ok(agg_inputs) => { + log_print!("\n=== Parsed Aggregated Public Inputs ==="); + log_print!("Asset ID: {}", agg_inputs.asset_id); + log_print!("Volume Fee BPS: {}", agg_inputs.volume_fee_bps); + log_print!( + "Block Hash: 0x{}", + hex::encode(agg_inputs.block_data.block_hash.as_ref()) + ); + log_print!("Block Number: {}", agg_inputs.block_data.block_number); + log_print!("\nAccount Data ({} accounts):", agg_inputs.account_data.len()); + for (i, acct) in agg_inputs.account_data.iter().enumerate() { + log_print!( + " [{}] amount={}, exit=0x{}", + i, + acct.summed_output_amount, + hex::encode(acct.exit_account.as_ref()) + ); + } + log_print!("\nNullifiers ({} nullifiers):", agg_inputs.nullifiers.len()); + for (i, nullifier) in agg_inputs.nullifiers.iter().enumerate() { + log_print!(" [{}] 0x{}", i, hex::encode(nullifier.as_ref())); + } + }, + Err(e) => { + log_print!("Failed to parse as aggregated inputs: {}", e); + }, + } + } else { + // Parse as leaf proof + let bins_dir = Path::new("generated-bins"); + let prover = qp_wormhole_prover::WormholeProver::new_from_files( + &bins_dir.join("prover.bin"), + &bins_dir.join("common.bin"), + ) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load prover: {}", e)) + })?; + + let common_data = &prover.circuit_data.common; + let proof = ProofWithPublicInputs::::from_bytes(proof_bytes, common_data) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to deserialize proof: {}", e)) + })?; + + log_print!("\nPublic inputs count: {}", proof.public_inputs.len()); + + let pi = PublicCircuitInputs::try_from(&proof).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to parse public inputs: {}", e)) + })?; + + log_print!("\n=== Parsed Leaf Public Inputs ==="); + log_print!("Asset ID: {}", pi.asset_id); + log_print!("Output Amount: {}", pi.output_amount); + log_print!("Volume Fee BPS: {}", pi.volume_fee_bps); + log_print!("Nullifier: 0x{}", hex::encode(pi.nullifier.as_ref())); + log_print!("Exit Account: 0x{}", hex::encode(pi.exit_account.as_ref())); + log_print!("Block Hash: 0x{}", hex::encode(pi.block_hash.as_ref())); + log_print!("Parent Hash: 0x{}", hex::encode(pi.parent_hash.as_ref())); + log_print!("Block Number: {}", pi.block_number); + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 684b112..c467064 100644 --- a/src/main.rs +++ b/src/main.rs @@ -72,15 +72,22 @@ async fn main() -> Result<(), QuantusError> { wait_for_transaction: cli.wait_for_transaction, }; - // Execute the command - match cli::execute_command(cli.command, &cli.node_url, cli.verbose, execution_mode).await { + // Execute the command with timing + let start_time = std::time::Instant::now(); + let result = + cli::execute_command(cli.command, &cli.node_url, cli.verbose, execution_mode).await; + let elapsed = start_time.elapsed(); + + match result { Ok(_) => { log_verbose!(""); log_verbose!("Command executed successfully!"); + log_print!("⏱️ Completed in {:.2}s", elapsed.as_secs_f64()); Ok(()) }, Err(e) => { log_error!("{}", e); + log_print!("⏱️ Failed after {:.2}s", elapsed.as_secs_f64()); std::process::exit(1); }, } diff --git a/tests/wormhole_integration.rs b/tests/wormhole_integration.rs index 7a2b873..c68acf5 100644 --- a/tests/wormhole_integration.rs +++ b/tests/wormhole_integration.rs @@ -22,7 +22,7 @@ use qp_wormhole_circuit::{ nullifier::Nullifier, }; use qp_wormhole_prover::WormholeProver; -use qp_wormhole_verifier::WormholeVerifier; + use qp_zk_circuits_common::{ circuit::{C, D, F}, storage_proof::prepare_proof_for_circuit, @@ -510,8 +510,6 @@ fn aggregate_proofs( ); let config = CircuitConfig::standard_recursion_zk_config(); - let verifier = WormholeVerifier::new(config.clone(), None); - let aggregation_config = TreeAggregationConfig::new(branching_factor, depth as u32); if proof_contexts.len() > aggregation_config.num_leaf_proofs { @@ -525,7 +523,7 @@ fn aggregate_proofs( } let mut aggregator = - WormholeProofAggregator::new(verifier.circuit_data).with_config(aggregation_config); + WormholeProofAggregator::from_circuit_config(config).with_config(aggregation_config); for (idx, ctx) in proof_contexts.into_iter().enumerate() { println!(" Adding proof {} to aggregator...", idx + 1); From 70b83428cb53d89a3ea34c0eb19b81d5ea339145 Mon Sep 17 00:00:00 2001 From: illuzen Date: Thu, 12 Feb 2026 03:26:06 +0800 Subject: [PATCH 03/26] agg proofs with multi-output work now --- Cargo.lock | 161 ++++-- Cargo.toml | 7 +- src/cli/wormhole.rs | 1121 +++++++++++++++++++++++++++++++++++++++- src/wallet/keystore.rs | 12 +- src/wallet/mod.rs | 35 +- 5 files changed, 1230 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fd20ba9..00adf6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1195,9 +1195,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -1298,9 +1298,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" dependencies = [ "powerfmt", ] @@ -1973,9 +1973,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -2829,7 +2829,6 @@ dependencies = [ "once_cell", "serdect", "sha2 0.10.9", - "signature", ] [[package]] @@ -3097,19 +3096,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "685a9ac4b61f4e728e1d2c6a7844609c16527aeb5e6c865915c08e619c16410f" -[[package]] -name = "nam-tiny-hderive" -version = "0.3.1-nam.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cd44792ed5cd84dc9dedc3d572242ac00e76c244e85eb4bf34da2c6239ce30" -dependencies = [ - "base58", - "hmac 0.12.1", - "k256", - "sha2 0.10.9", - "zeroize", -] - [[package]] name = "nodrop" version = "0.1.14" @@ -3577,6 +3563,8 @@ dependencies = [ [[package]] name = "plonky2_maybe_rayon" version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1e554181dc95243b8d9948ae7bae5759c7fb2502fed28f671f95ef38079406" dependencies = [ "rayon", ] @@ -3585,6 +3573,12 @@ dependencies = [ name = "plonky2_util" version = "1.0.0" +[[package]] +name = "plonky2_util" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c32c137808ca984ab2458b612b7eb0462d853ee041a3136e83d54b96074c7610" + [[package]] name = "polkavm-common" version = "0.24.0" @@ -3815,8 +3809,6 @@ dependencies = [ [[package]] name = "qp-dilithium-crypto" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb2f13d8793f7a79c42d33e4ebe9d470fe938dc55592ef97ef42d4298aa6a976" dependencies = [ "log", "parity-scale-codec", @@ -3832,7 +3824,9 @@ dependencies = [ [[package]] name = "qp-plonky2" -version = "1.1.3" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "593bccf15b8e2f9eb904ef4010f68b81ddcceb70aaf90116ce29ec09d7578dd4" dependencies = [ "ahash", "anyhow", @@ -3847,10 +3841,10 @@ dependencies = [ "p3-poseidon2", "p3-symmetric", "plonky2_maybe_rayon", - "plonky2_util", - "qp-plonky2-core", - "qp-plonky2-field", - "qp-plonky2-verifier", + "plonky2_util 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-plonky2-core 1.1.5", + "qp-plonky2-field 1.1.5", + "qp-plonky2-verifier 1.1.5", "qp-poseidon-constants", "rand 0.8.5", "rand_chacha 0.3.1", @@ -3875,8 +3869,33 @@ dependencies = [ "p3-goldilocks", "p3-poseidon2", "p3-symmetric", - "plonky2_util", - "qp-plonky2-field", + "plonky2_util 1.0.0", + "qp-plonky2-field 1.1.3", + "qp-poseidon-constants", + "serde", + "static_assertions", + "unroll", +] + +[[package]] +name = "qp-plonky2-core" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d30fabfd90e359640f2371c8b3e9b377d215f7dcf4e61da1f38776c5b84540" +dependencies = [ + "ahash", + "anyhow", + "hashbrown 0.14.5", + "itertools 0.11.0", + "keccak-hash 0.8.0", + "log", + "num", + "p3-field", + "p3-goldilocks", + "p3-poseidon2", + "p3-symmetric", + "plonky2_util 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-plonky2-field 1.1.5", "qp-poseidon-constants", "rand 0.8.5", "serde", @@ -3891,7 +3910,23 @@ dependencies = [ "anyhow", "itertools 0.11.0", "num", - "plonky2_util", + "plonky2_util 1.0.0", + "rustc_version", + "serde", + "static_assertions", + "unroll", +] + +[[package]] +name = "qp-plonky2-field" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20c9f8259bf4f220b1d81001458cc6c09a1372f2b3e8dac2fb489a66230385c3" +dependencies = [ + "anyhow", + "itertools 0.11.0", + "num", + "plonky2_util 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.8.5", "rustc_version", "serde", @@ -3899,6 +3934,32 @@ dependencies = [ "unroll", ] +[[package]] +name = "qp-plonky2-verifier" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0eb89fd3cc40c4b25be95399635957d416406328169ba939db989c0444f364" +dependencies = [ + "ahash", + "anyhow", + "hashbrown 0.14.5", + "itertools 0.11.0", + "keccak-hash 0.8.0", + "log", + "num", + "p3-field", + "p3-goldilocks", + "p3-poseidon2", + "p3-symmetric", + "plonky2_util 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-plonky2-core 1.1.5", + "qp-plonky2-field 1.1.5", + "qp-poseidon-constants", + "serde", + "static_assertions", + "unroll", +] + [[package]] name = "qp-plonky2-verifier" version = "2.0.0" @@ -3914,9 +3975,9 @@ dependencies = [ "p3-goldilocks", "p3-poseidon2", "p3-symmetric", - "plonky2_util", - "qp-plonky2-core", - "qp-plonky2-field", + "plonky2_util 1.0.0", + "qp-plonky2-core 1.0.0", + "qp-plonky2-field 1.1.3", "qp-poseidon-constants", "serde", "static_assertions", @@ -3972,33 +4033,33 @@ dependencies = [ [[package]] name = "qp-rusty-crystals-dilithium" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a42bfb3430fa3bf3f5a148f8132de301876ceb1bdf0891909c2728f044a58" +checksum = "d734438e080d69fa186dac23565dd261fa8146048af00ba8aea7467b429c104b" dependencies = [ - "aes", - "cipher", - "sha2 0.10.9", - "subtle", + "zeroize", ] [[package]] name = "qp-rusty-crystals-hdwallet" -version = "1.0.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fa242963fcd6bc970948b6904f18074673ff89cab8ed0133846a53c69deca7" +checksum = "74d9d8eb6c6a555c831496ab14348a41e4d23aa11943930a568891bf687cd8b1" dependencies = [ "bip39", + "bs58", + "getrandom 0.2.17", "hex", "hex-literal", - "nam-tiny-hderive", + "hmac 0.12.1", + "k256", "qp-poseidon-core", "qp-rusty-crystals-dilithium", - "rand_chacha 0.9.0", - "rand_core 0.9.5", "serde", "serde_json", + "sha2 0.10.9", "thiserror 2.0.18", + "zeroize", ] [[package]] @@ -4047,7 +4108,7 @@ name = "qp-wormhole-verifier" version = "1.0.1" dependencies = [ "anyhow", - "qp-plonky2-verifier", + "qp-plonky2-verifier 2.0.0", "qp-wormhole-inputs", ] @@ -4105,7 +4166,7 @@ dependencies = [ "test-helpers", "thiserror 2.0.18", "tokio", - "toml 0.9.11+spec-1.1.0", + "toml 0.9.12+spec-1.1.0", ] [[package]] @@ -6176,9 +6237,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.11+spec-1.1.0" +version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ "indexmap", "serde_core", @@ -6235,9 +6296,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.0.7+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1" dependencies = [ "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index 279f9eb..da8491f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,8 +49,8 @@ rand = "0.9" aes-gcm = "0.10" # AES-256-GCM (quantum-safe with 256-bit keys) # Quantus crypto dependencies -qp-rusty-crystals-dilithium = { version = "2.0.0" } -qp-rusty-crystals-hdwallet = { version = "1.0.0" } +qp-rusty-crystals-dilithium = { version = "2.1.0" } +qp-rusty-crystals-hdwallet = { version = "1.3.0" } qp-poseidon = { version = "1.0.7", features = [ "serde", ] } @@ -98,5 +98,4 @@ qp-zk-circuits-common = { path = "../qp-zk-circuits/common" } test-helpers = { path = "../qp-zk-circuits/wormhole/tests/test-helpers" } [patch.crates-io] -qp-plonky2 = { path = "../qp-plonky2/plonky2" } -qp-plonky2-field = { path = "../qp-plonky2/field" } +qp-dilithium-crypto = { path = "../chain/primitives/dilithium-crypto" } diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index d8ed622..7774cf4 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -4,12 +4,18 @@ use crate::{ quantus_subxt::{self as quantus_node, api::wormhole}, }, cli::common::{submit_transaction, ExecutionMode}, + cli::send::get_balance, log_error, log_print, log_success, log_verbose, - wallet::QuantumKeyPair, + wallet::{password, QuantumKeyPair, WalletManager}, }; use clap::Subcommand; -use plonky2::plonk::{circuit_data::CircuitConfig, proof::ProofWithPublicInputs}; +use indicatif::{ProgressBar, ProgressStyle}; +use plonky2::plonk::proof::ProofWithPublicInputs; use qp_poseidon::PoseidonHasher; +use qp_rusty_crystals_hdwallet::{ + derive_wormhole_from_mnemonic, generate_mnemonic, SensitiveBytes32, WormholePair, + QUANTUS_WORMHOLE_CHAIN_ID, +}; use qp_wormhole_circuit::{ inputs::{ AggregatedPublicCircuitInputs, CircuitInputs, PrivateCircuitInputs, PublicCircuitInputs, @@ -17,16 +23,17 @@ use qp_wormhole_circuit::{ nullifier::Nullifier, }; use qp_wormhole_prover::WormholeProver; -use qp_wormhole_verifier::WormholeVerifier; use qp_zk_circuits_common::{ circuit::{C, D, F}, storage_proof::prepare_proof_for_circuit, utils::{BytesDigest, Digest}, }; +use rand::RngCore; use sp_core::{ crypto::{AccountId32, Ss58Codec}, Hasher, }; +use std::path::Path; use subxt::{ backend::legacy::rpc_methods::ReadProof, blocks::Block, @@ -369,6 +376,44 @@ pub enum WormholeCommands { #[arg(long)] aggregated: bool, }, + /// Run a multi-round wormhole test: wallet -> wormhole -> ... -> wallet + Multiround { + /// Number of proofs per round (default: 2, max: 8) + #[arg(short, long, default_value = "2")] + num_proofs: usize, + + /// Number of rounds (default: 2) + #[arg(short, long, default_value = "2")] + rounds: usize, + + /// Amount per transfer in planck (default: 10 DEV) + #[arg(short, long, default_value = "10000000000000")] + amount: u128, + + /// Wallet name to use for funding and final exit + #[arg(short, long)] + wallet: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + + /// Keep proof files after completion + #[arg(short, long)] + keep_files: bool, + + /// Output directory for proof files + #[arg(short, long, default_value = "/tmp/wormhole_multiround")] + output_dir: String, + + /// Dry run - show what would be done without executing + #[arg(long)] + dry_run: bool, + }, } pub async fn handle_wormhole_command( @@ -376,8 +421,9 @@ pub async fn handle_wormhole_command( node_url: &str, ) -> crate::error::Result<()> { match command { - WormholeCommands::Transfer { secret, amount, from, password, password_file } => - submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await, + WormholeCommands::Transfer { secret, amount, from, password, password_file } => { + submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await + }, WormholeCommands::Generate { secret, amount, @@ -386,7 +432,7 @@ pub async fn handle_wormhole_command( transfer_count, funding_account, output, - } => + } => { generate_proof( secret, amount, @@ -397,14 +443,43 @@ pub async fn handle_wormhole_command( output, node_url, ) - .await, + .await + }, WormholeCommands::Verify { proof } => verify_proof(proof, node_url).await, - WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => - aggregate_proofs(proofs, output, depth, branching_factor).await, - WormholeCommands::VerifyAggregated { proof } => - verify_aggregated_proof(proof, node_url).await, - WormholeCommands::ParseProof { proof, aggregated } => - parse_proof_file(proof, aggregated).await, + WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => { + aggregate_proofs(proofs, output, depth, branching_factor).await + }, + WormholeCommands::VerifyAggregated { proof } => { + verify_aggregated_proof(proof, node_url).await + }, + WormholeCommands::ParseProof { proof, aggregated } => { + parse_proof_file(proof, aggregated).await + }, + WormholeCommands::Multiround { + num_proofs, + rounds, + amount, + wallet, + password, + password_file, + keep_files, + output_dir, + dry_run, + } => { + run_multiround( + num_proofs, + rounds, + amount, + wallet, + password, + password_file, + keep_files, + output_dir, + dry_run, + node_url, + ) + .await + }, } } @@ -665,11 +740,14 @@ async fn generate_proof( input_amount: input_amount_quantized, }, public: PublicCircuitInputs { - output_amount: output_amount_quantized, + output_amount_1: output_amount_quantized, + output_amount_2: 0, // No change output for single-output spend volume_fee_bps: VOLUME_FEE_BPS, nullifier: Nullifier::from_preimage(secret, transfer_count).hash.into(), - exit_account: BytesDigest::try_from(exit_account_id.as_ref() as &[u8]) + exit_account_1: BytesDigest::try_from(exit_account_id.as_ref() as &[u8]) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, + exit_account_2: BytesDigest::try_from([0u8; 32].as_ref()) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, // Unused block_hash: BytesDigest::try_from(block_hash.as_ref()) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, parent_hash, @@ -800,6 +878,28 @@ async fn aggregate_proofs( log_verbose!("Aggregated public inputs: {:#?}", aggregated_public_inputs); + // Log exit accounts and amounts that will be minted + log_print!(" Exit accounts in aggregated proof:"); + for (idx, account_data) in aggregated_public_inputs.account_data.iter().enumerate() { + let exit_bytes: &[u8] = account_data.exit_account.as_ref(); + let is_dummy = exit_bytes.iter().all(|&b| b == 0) || account_data.summed_output_amount == 0; + if is_dummy { + log_verbose!(" [{}] DUMMY (skipped)", idx); + } else { + // De-quantize to show actual amount that will be minted + let dequantized_amount = + (account_data.summed_output_amount as u128) * SCALE_DOWN_FACTOR; + log_print!( + " [{}] {} -> {} quantized ({} planck = {})", + idx, + hex::encode(exit_bytes), + account_data.summed_output_amount, + dequantized_amount, + format_balance(dequantized_amount) + ); + } + } + // Verify the aggregated proof locally log_verbose!("Verifying aggregated proof locally..."); aggregated_proof @@ -1050,6 +1150,972 @@ async fn verify_proof(proof_file: String, node_url: &str) -> crate::error::Resul Err(crate::error::QuantusError::Generic("Transaction stream ended unexpectedly".to_string())) } +// ============================================================================ +// Multi-round wormhole flow implementation +// ============================================================================ + +/// Aggregation config - hardcoded for now +const MULTIROUND_BRANCHING_FACTOR: usize = 2; +const MULTIROUND_DEPTH: usize = 3; +const MULTIROUND_MAX_PROOFS: usize = 8; // 2^3 + +/// Information about a transfer needed for proof generation +#[derive(Debug, Clone)] +#[allow(dead_code)] +struct TransferInfo { + /// Block hash where the transfer was included + block_hash: subxt::utils::H256, + /// Transfer count for this specific transfer + transfer_count: u64, + /// Amount transferred + amount: u128, + /// The wormhole address (destination of transfer) + wormhole_address: SubxtAccountId, + /// The funding account (source of transfer) + funding_account: SubxtAccountId, +} + +/// Derive a wormhole secret using HD derivation +/// Path: m/44'/189189189'/0'/round'/index' +fn derive_wormhole_secret( + mnemonic: &str, + round: usize, + index: usize, +) -> Result { + // QUANTUS_WORMHOLE_CHAIN_ID already includes the ' (e.g., "189189189'") + let path = format!("m/44'/{}/0'/{}'/{}'", QUANTUS_WORMHOLE_CHAIN_ID, round, index); + derive_wormhole_from_mnemonic(mnemonic, None, &path) + .map_err(|e| crate::error::QuantusError::Generic(format!("HD derivation failed: {:?}", e))) +} + +/// Calculate the amount for a given round, accounting for fees +/// Each round deducts 0.1% fee (10 bps) +/// Round 1: fee applied once, Round 2: fee applied twice, etc. +fn calculate_round_amount(initial_amount: u128, round: usize) -> u128 { + let mut amount = initial_amount; + for _ in 0..round { + // Output = Input * (10000 - 10) / 10000 + amount = amount * 9990 / 10000; + } + amount +} + +/// Get the minting account from chain constants +async fn get_minting_account( + client: &OnlineClient, +) -> Result { + let minting_account_addr = quantus_node::api::constants().wormhole().minting_account(); + let minting_account = client.constants().at(&minting_account_addr).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get minting account: {}", e)) + })?; + Ok(minting_account) +} + +/// Parse transfer info from NativeTransferred events in a block +fn parse_transfer_events( + events: &[wormhole::events::NativeTransferred], + expected_addresses: &[SubxtAccountId], +) -> Result, crate::error::QuantusError> { + let mut transfer_infos = Vec::new(); + + for expected_addr in expected_addresses { + // Find the event matching this address + let matching_event = events.iter().find(|e| &e.to == expected_addr).ok_or_else(|| { + crate::error::QuantusError::Generic(format!( + "No transfer event found for address {:?}", + expected_addr + )) + })?; + + transfer_infos.push(TransferInfo { + block_hash: subxt::utils::H256::default(), // Will be set by caller + transfer_count: matching_event.transfer_count, + amount: matching_event.amount, + wormhole_address: expected_addr.clone(), + funding_account: matching_event.from.clone(), + }); + } + + Ok(transfer_infos) +} + +/// Run the multi-round wormhole flow +#[allow(clippy::too_many_arguments)] +async fn run_multiround( + num_proofs: usize, + rounds: usize, + amount: u128, + wallet_name: String, + password: Option, + password_file: Option, + keep_files: bool, + output_dir: String, + dry_run: bool, + node_url: &str, +) -> crate::error::Result<()> { + use colored::Colorize; + + log_print!(""); + log_print!("=================================================="); + log_print!(" Wormhole Multi-Round Flow Test"); + log_print!("=================================================="); + log_print!(""); + + // Validate parameters + if num_proofs < 1 || num_proofs > MULTIROUND_MAX_PROOFS { + return Err(crate::error::QuantusError::Generic(format!( + "num_proofs must be between 1 and {} (got: {})", + MULTIROUND_MAX_PROOFS, num_proofs + ))); + } + if rounds < 1 { + return Err(crate::error::QuantusError::Generic(format!( + "rounds must be at least 1 (got: {})", + rounds + ))); + } + + // Load wallet + let wallet_manager = WalletManager::new()?; + let wallet_password = password::get_wallet_password(&wallet_name, password, password_file)?; + let wallet_data = wallet_manager.load_wallet(&wallet_name, &wallet_password)?; + let wallet_address = wallet_data.keypair.to_account_id_ss58check(); + let wallet_account_id = SubxtAccountId(wallet_data.keypair.to_account_id_32().into()); + + // Get or generate mnemonic for HD derivation + let mnemonic = match wallet_data.mnemonic { + Some(m) => { + log_verbose!("Using wallet mnemonic for HD derivation"); + m + }, + None => { + log_print!("Wallet has no mnemonic - generating random mnemonic for wormhole secrets"); + let mut entropy = [0u8; 32]; + rand::rng().fill_bytes(&mut entropy); + let sensitive_entropy = SensitiveBytes32::from(&mut entropy); + let m = generate_mnemonic(sensitive_entropy).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to generate mnemonic: {:?}", e)) + })?; + log_verbose!("Generated mnemonic (not saved): {}", m); + m + }, + }; + + log_print!("{}", "Configuration:".bright_cyan()); + log_print!(" Wallet: {}", wallet_name); + log_print!(" Wallet address: {}", wallet_address); + log_print!(" Initial amount: {} ({})", amount, format_balance(amount)); + log_print!(" Proofs per round: {}", num_proofs); + log_print!(" Rounds: {}", rounds); + log_print!( + " Aggregation: branching_factor={}, depth={}", + MULTIROUND_BRANCHING_FACTOR, + MULTIROUND_DEPTH + ); + log_print!(" Output directory: {}", output_dir); + log_print!(" Keep files: {}", keep_files); + log_print!(" Dry run: {}", dry_run); + log_print!(""); + + // Show expected amounts per round + log_print!("{}", "Expected amounts per round:".bright_cyan()); + for r in 1..=rounds { + let round_amount = calculate_round_amount(amount, r); + log_print!(" Round {}: {} ({})", r, round_amount, format_balance(round_amount)); + } + log_print!(""); + + // Create output directory + std::fs::create_dir_all(&output_dir).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to create output directory: {}", e)) + })?; + + if dry_run { + return run_multiround_dry_run(&mnemonic, num_proofs, rounds, amount, &wallet_address); + } + + // Connect to node + let quantus_client = QuantusClient::new(node_url).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to connect to node: {}", e)) + })?; + let client = quantus_client.client(); + + // Get minting account from chain + let minting_account = get_minting_account(client).await?; + log_verbose!("Minting account: {:?}", minting_account); + + // Record initial wallet balance for verification + let initial_balance = get_balance(&quantus_client, &wallet_address).await?; + log_print!("{}", "Initial Balance:".bright_cyan()); + log_print!(" Wallet balance: {} ({})", initial_balance, format_balance(initial_balance)); + log_print!(""); + + // Track transfer info for the current round + let mut current_transfers: Vec = Vec::new(); + + for round in 1..=rounds { + let is_final = round == rounds; + + log_print!(""); + log_print!("--------------------------------------------------"); + log_print!( + " {} Round {} of {} {}", + ">>>".bright_blue(), + round, + rounds, + "<<<".bright_blue() + ); + log_print!("--------------------------------------------------"); + log_print!(""); + + // Create round output directory + let round_dir = format!("{}/round{}", output_dir, round); + std::fs::create_dir_all(&round_dir).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to create round directory: {}", e)) + })?; + + // Derive secrets for this round + let pb = ProgressBar::new(num_proofs as u64); + pb.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") + .unwrap() + .progress_chars("#>-"), + ); + pb.set_message("Deriving secrets..."); + + let mut secrets: Vec = Vec::new(); + for i in 1..=num_proofs { + let secret = derive_wormhole_secret(&mnemonic, round, i)?; + secrets.push(secret); + pb.inc(1); + } + pb.finish_with_message("Secrets derived"); + + // Determine exit accounts + let exit_accounts: Vec = if is_final { + log_print!("Final round - all proofs exit to wallet: {}", wallet_address); + vec![wallet_account_id.clone(); num_proofs] + } else { + log_print!( + "Intermediate round - proofs exit to round {} wormhole addresses", + round + 1 + ); + let mut addrs = Vec::new(); + for i in 1..=num_proofs { + let next_secret = derive_wormhole_secret(&mnemonic, round + 1, i)?; + addrs.push(SubxtAccountId(next_secret.address)); + } + addrs + }; + + // Step 1: Get transfer info + if round == 1 { + log_print!("{}", "Step 1: Sending wormhole transfers from wallet...".bright_yellow()); + + let pb = ProgressBar::new(num_proofs as u64); + pb.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") + .unwrap() + .progress_chars("#>-"), + ); + + current_transfers.clear(); + for (i, secret) in secrets.iter().enumerate() { + pb.set_message(format!("Transfer {}/{}", i + 1, num_proofs)); + + let wormhole_address = SubxtAccountId(secret.address); + + // Submit transfer + let transfer_tx = quantus_node::api::tx().wormhole().transfer_native( + subxt::ext::subxt_core::utils::MultiAddress::Id(wormhole_address.clone()), + amount, + ); + + let quantum_keypair = QuantumKeyPair { + public_key: wallet_data.keypair.public_key.clone(), + private_key: wallet_data.keypair.private_key.clone(), + }; + + submit_transaction( + &quantus_client, + &quantum_keypair, + transfer_tx, + None, + ExecutionMode { finalized: false, wait_for_transaction: true }, + ) + .await + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Transfer failed: {}", e)) + })?; + + // Get the block and find our event + let block = at_best_block(&quantus_client).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) + })?; + let block_hash = block.hash(); + + let events_api = client.events().at(block_hash).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get events: {}", e)) + })?; + + // Find our transfer event + let event = events_api + .find::() + .find(|e| if let Ok(evt) = e { evt.to.0 == secret.address } else { false }) + .ok_or_else(|| { + crate::error::QuantusError::Generic( + "No matching transfer event found".to_string(), + ) + })? + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Event decode error: {}", e)) + })?; + + let funding_account_bytes = wallet_data.keypair.to_account_id_32(); + current_transfers.push(TransferInfo { + block_hash, + transfer_count: event.transfer_count, + amount, + wormhole_address, + funding_account: SubxtAccountId(funding_account_bytes.into()), + }); + + pb.inc(1); + } + pb.finish_with_message("Transfers complete"); + + // Log balance immediately after funding transfers + let balance_after_funding = get_balance(&quantus_client, &wallet_address).await?; + let funding_deducted = initial_balance.saturating_sub(balance_after_funding); + log_print!( + " Balance after funding: {} ({}) [deducted: {} planck]", + balance_after_funding, + format_balance(balance_after_funding), + funding_deducted + ); + } else { + log_print!("{}", "Step 1: Using transfer info from previous round...".bright_yellow()); + // current_transfers was populated from the previous round's verification events + // The secrets for this round ARE the exit secrets from round-1 + // So current_transfers already has the right wormhole addresses + log_print!(" Found {} transfer(s) from previous round", current_transfers.len()); + } + + // Step 2: Generate proofs + log_print!("{}", "Step 2: Generating proofs...".bright_yellow()); + + // All proofs in an aggregation batch must use the same block for storage proofs. + // Use the best block (which contains all transfers' state) for all proofs. + let proof_block = at_best_block(&quantus_client).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) + })?; + let proof_block_hash = proof_block.hash(); + log_print!(" Using block {} for all proofs", hex::encode(proof_block_hash.0)); + + let pb = ProgressBar::new(num_proofs as u64); + pb.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") + .unwrap() + .progress_chars("#>-"), + ); + + let mut proof_files: Vec = Vec::new(); + for (i, (secret, transfer)) in secrets.iter().zip(current_transfers.iter()).enumerate() { + pb.set_message(format!("Proof {}/{}", i + 1, num_proofs)); + + let proof_file = format!("{}/proof_{}.hex", round_dir, i + 1); + let exit_account_hex = format!("0x{}", hex::encode(exit_accounts[i].0)); + + // Use the funding account from the transfer info + let funding_account_hex = format!("0x{}", hex::encode(transfer.funding_account.0)); + + // Generate proof using internal function + // Use the actual transfer amount (not calculated round_amount) for storage key lookup + // All proofs use the same block hash for aggregation compatibility + generate_proof_internal( + &hex::encode(secret.secret), + transfer.amount, // Use actual transfer amount for storage key + &exit_account_hex, + &format!("0x{}", hex::encode(proof_block_hash.0)), + transfer.transfer_count, + &funding_account_hex, + &proof_file, + &quantus_client, + ) + .await?; + + proof_files.push(proof_file); + pb.inc(1); + } + pb.finish_with_message("Proofs generated"); + + // Step 3: Aggregate proofs + log_print!("{}", "Step 3: Aggregating proofs...".bright_yellow()); + + let aggregated_file = format!("{}/aggregated.hex", round_dir); + aggregate_proofs( + proof_files, + aggregated_file.clone(), + MULTIROUND_DEPTH, + MULTIROUND_BRANCHING_FACTOR, + ) + .await?; + + log_print!(" Aggregated proof saved to {}", aggregated_file); + + // Step 4: Verify aggregated proof on-chain + log_print!("{}", "Step 4: Submitting aggregated proof on-chain...".bright_yellow()); + + let (verification_block, transfer_events) = + verify_aggregated_and_get_events(&aggregated_file, &quantus_client).await?; + + log_print!( + " {} Proof verified in block {}", + "✓".bright_green(), + hex::encode(verification_block.0) + ); + + // If not final round, prepare transfer info for next round + if !is_final { + log_print!("{}", "Step 5: Capturing transfer info for next round...".bright_yellow()); + + // Parse events to get transfer info for next round's wormhole addresses + let next_round_addresses: Vec = (1..=num_proofs) + .map(|i| { + let next_secret = derive_wormhole_secret(&mnemonic, round + 1, i).unwrap(); + SubxtAccountId(next_secret.address) + }) + .collect(); + + current_transfers = parse_transfer_events(&transfer_events, &next_round_addresses)?; + + // Update block hash for all transfers + for transfer in &mut current_transfers { + transfer.block_hash = verification_block; + } + + log_print!( + " Captured {} transfer(s) for round {}", + current_transfers.len(), + round + 1 + ); + } + + // Log balance after this round + let balance_after_round = get_balance(&quantus_client, &wallet_address).await?; + let change_from_initial = balance_after_round as i128 - initial_balance as i128; + let change_str = if change_from_initial >= 0 { + format!("+{}", change_from_initial) + } else { + format!("{}", change_from_initial) + }; + log_print!(""); + log_print!( + " Balance after round {}: {} ({}) [change: {} planck]", + round, + balance_after_round, + format_balance(balance_after_round), + change_str + ); + + log_print!(""); + log_print!(" {} Round {} complete!", "✓".bright_green(), round); + } + + log_print!(""); + log_print!("=================================================="); + log_success!(" All {} rounds completed successfully!", rounds); + log_print!("=================================================="); + log_print!(""); + + // Final balance verification + log_print!("{}", "Balance Verification:".bright_cyan()); + + // Query final balance + let final_balance = get_balance(&quantus_client, &wallet_address).await?; + + // Calculate expected balance change + // Total sent in round 1: num_proofs * amount + let total_sent = (num_proofs as u128) * amount; + + // Total received in final round: num_proofs * final_round_amount + let final_round_amount = calculate_round_amount(amount, rounds); + let total_received = (num_proofs as u128) * final_round_amount; + + // Expected net change (may be negative due to fees) + let expected_change = total_received as i128 - total_sent as i128; + let actual_change = final_balance as i128 - initial_balance as i128; + + log_print!(" Initial balance: {} ({})", initial_balance, format_balance(initial_balance)); + log_print!(" Final balance: {} ({})", final_balance, format_balance(final_balance)); + log_print!(""); + log_print!(" Total sent (round 1): {} ({})", total_sent, format_balance(total_sent)); + log_print!( + " Total received (round {}): {} ({})", + rounds, + total_received, + format_balance(total_received) + ); + log_print!(""); + + // Format signed amounts for display + let expected_change_str = if expected_change >= 0 { + format!("+{}", expected_change) + } else { + format!("{}", expected_change) + }; + let actual_change_str = if actual_change >= 0 { + format!("+{}", actual_change) + } else { + format!("{}", actual_change) + }; + + log_print!(" Expected change: {} planck", expected_change_str); + log_print!(" Actual change: {} planck", actual_change_str); + log_print!(""); + + // Allow some tolerance for transaction fees (e.g., 1% or a fixed amount) + // The actual change may differ slightly due to transaction fees for the initial transfers + let tolerance = (total_sent / 100).max(1_000_000_000_000); // 1% or 1 QNT minimum + + let diff = (actual_change - expected_change).abs() as u128; + if diff <= tolerance { + log_success!( + " {} Balance verification PASSED (within tolerance of {} planck)", + "✓".bright_green(), + tolerance + ); + } else { + log_print!( + " {} Balance verification: difference of {} planck (tolerance: {} planck)", + "!".bright_yellow(), + diff, + tolerance + ); + log_print!( + " Note: Transaction fees for {} initial transfers may account for the difference", + num_proofs + ); + } + log_print!(""); + + if keep_files { + log_print!("Proof files preserved in: {}", output_dir); + } else { + log_print!("Cleaning up proof files..."); + std::fs::remove_dir_all(&output_dir).ok(); + } + + Ok(()) +} + +/// Internal proof generation that uses already-connected client +#[allow(clippy::too_many_arguments)] +async fn generate_proof_internal( + secret_hex: &str, + funding_amount: u128, + exit_account_str: &str, + block_hash_str: &str, + transfer_count: u64, + funding_account_str: &str, + output_file: &str, + quantus_client: &QuantusClient, +) -> crate::error::Result<()> { + // Parse secret + let secret_array = parse_secret_hex(secret_hex).map_err(crate::error::QuantusError::Generic)?; + let secret: BytesDigest = secret_array.try_into().map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to convert secret: {:?}", e)) + })?; + + // Parse exit account + let exit_account_bytes = + parse_exit_account(exit_account_str).map_err(crate::error::QuantusError::Generic)?; + let exit_account_id = SubxtAccountId(exit_account_bytes); + + // Parse funding account + let funding_account_bytes = + parse_exit_account(funding_account_str).map_err(crate::error::QuantusError::Generic)?; + let funding_account = AccountId32::new(funding_account_bytes); + + // Parse block hash + let hash_bytes = hex::decode(block_hash_str.trim_start_matches("0x")) + .map_err(|e| crate::error::QuantusError::Generic(format!("Invalid block hash: {}", e)))?; + if hash_bytes.len() != 32 { + return Err(crate::error::QuantusError::Generic(format!( + "Block hash must be 32 bytes, got {}", + hash_bytes.len() + ))); + } + let hash: [u8; 32] = hash_bytes.try_into().unwrap(); + let block_hash = subxt::utils::H256::from(hash); + + let client = quantus_client.client(); + + // Generate unspendable account from secret + let unspendable_account = + qp_wormhole_circuit::unspendable_account::UnspendableAccount::from_secret(secret) + .account_id; + let unspendable_account_bytes_digest = + qp_zk_circuits_common::utils::digest_felts_to_bytes(unspendable_account); + let unspendable_account_bytes: [u8; 32] = unspendable_account_bytes_digest + .as_ref() + .try_into() + .expect("BytesDigest is always 32 bytes"); + + let from_account = funding_account.clone(); + let to_account = AccountId32::new(unspendable_account_bytes); + + // Get block + let blocks = + client.blocks().at(block_hash).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) + })?; + + // Build storage key + let leaf_hash = qp_poseidon::PoseidonHasher::hash_storage::( + &( + NATIVE_ASSET_ID, + transfer_count, + from_account.clone(), + to_account.clone(), + funding_amount, + ) + .encode(), + ); + + let proof_address = quantus_node::api::storage().wormhole().transfer_proof(( + NATIVE_ASSET_ID, + transfer_count, + SubxtAccountId(from_account.clone().into()), + SubxtAccountId(to_account.clone().into()), + funding_amount, + )); + + let mut final_key = proof_address.to_root_bytes(); + final_key.extend_from_slice(&leaf_hash); + + // Verify storage key exists + let storage_api = client.storage().at(block_hash); + let val = storage_api + .fetch_raw(final_key.clone()) + .await + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; + if val.is_none() { + return Err(crate::error::QuantusError::Generic( + "Storage key not found - transfer may not exist in this block".to_string(), + )); + } + + // Get storage proof + let proof_params = rpc_params![vec![to_hex(&final_key)], block_hash]; + let read_proof: ReadProof = quantus_client + .rpc_client() + .request("state_getReadProof", proof_params) + .await + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; + + let header = blocks.header(); + let state_root = BytesDigest::try_from(header.state_root.as_bytes()) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; + let parent_hash = BytesDigest::try_from(header.parent_hash.as_bytes()) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; + let extrinsics_root = BytesDigest::try_from(header.extrinsics_root.as_bytes()) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; + let digest = + header.digest.encode().try_into().map_err(|_| { + crate::error::QuantusError::Generic("Failed to encode digest".to_string()) + })?; + let block_number = header.number; + + // Prepare storage proof + let processed_storage_proof = prepare_proof_for_circuit( + read_proof.proof.iter().map(|proof| proof.0.clone()).collect(), + hex::encode(header.state_root.0), + leaf_hash, + ) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; + + // Quantize amounts + let input_amount_quantized: u32 = + quantize_funding_amount(funding_amount).map_err(crate::error::QuantusError::Generic)?; + let output_amount_quantized = compute_output_amount(input_amount_quantized, VOLUME_FEE_BPS); + + let inputs = CircuitInputs { + private: PrivateCircuitInputs { + secret, + transfer_count, + funding_account: BytesDigest::try_from(funding_account.as_ref() as &[u8]) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, + storage_proof: processed_storage_proof, + unspendable_account: Digest::from(unspendable_account).into(), + state_root, + extrinsics_root, + digest, + input_amount: input_amount_quantized, + }, + public: PublicCircuitInputs { + output_amount_1: output_amount_quantized, + output_amount_2: 0, // No change output for single-output spend + volume_fee_bps: VOLUME_FEE_BPS, + nullifier: Nullifier::from_preimage(secret, transfer_count).hash.into(), + exit_account_1: BytesDigest::try_from(exit_account_id.as_ref() as &[u8]) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, + exit_account_2: BytesDigest::try_from([0u8; 32].as_ref()) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, // Unused + block_hash: BytesDigest::try_from(block_hash.as_ref()) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, + parent_hash, + block_number, + asset_id: NATIVE_ASSET_ID, + }, + }; + + // Load prover from pre-built bins + let bins_dir = Path::new("generated-bins"); + let prover = + WormholeProver::new_from_files(&bins_dir.join("prover.bin"), &bins_dir.join("common.bin")) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load prover: {}", e)) + })?; + let prover_next = prover + .commit(&inputs) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; + let proof: ProofWithPublicInputs<_, _, 2> = prover_next.prove().map_err(|e| { + crate::error::QuantusError::Generic(format!("Proof generation failed: {}", e)) + })?; + + let proof_hex = hex::encode(proof.to_bytes()); + std::fs::write(output_file, proof_hex).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to write proof: {}", e)) + })?; + + Ok(()) +} + +/// Verify an aggregated proof and return the block hash and transfer events +async fn verify_aggregated_and_get_events( + proof_file: &str, + quantus_client: &QuantusClient, +) -> crate::error::Result<(subxt::utils::H256, Vec)> { + use crate::chain::quantus_subxt::api::system::events::ExtrinsicFailed; + use qp_wormhole_verifier::WormholeVerifier; + use subxt::tx::TxStatus; + + // Read proof from file + let proof_hex = std::fs::read_to_string(proof_file).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to read proof file: {}", e)) + })?; + + let proof_bytes = hex::decode(proof_hex.trim()) + .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to decode hex: {}", e)))?; + + // Verify locally before submitting on-chain + log_verbose!("Verifying aggregated proof locally before on-chain submission..."); + let aggregated_verifier_bytes = include_bytes!("../../generated-bins/aggregated_verifier.bin"); + let aggregated_common_bytes = include_bytes!("../../generated-bins/aggregated_common.bin"); + let verifier = + WormholeVerifier::new_from_bytes(aggregated_verifier_bytes, aggregated_common_bytes) + .map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to load aggregated verifier: {}", + e + )) + })?; + + // Use the verifier crate's ProofWithPublicInputs type (different from plonky2's) + let proof = qp_wormhole_verifier::ProofWithPublicInputs::< + qp_wormhole_verifier::F, + qp_wormhole_verifier::C, + { qp_wormhole_verifier::D }, + >::from_bytes(proof_bytes.clone(), &verifier.circuit_data.common) + .map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to deserialize aggregated proof: {}", + e + )) + })?; + + verifier.verify(proof).map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Local aggregated proof verification failed: {}", + e + )) + })?; + log_verbose!("Local verification passed!"); + + // Create the verify_aggregated_proof transaction payload + let verify_tx = quantus_node::api::tx().wormhole().verify_aggregated_proof(proof_bytes); + + // Submit as unsigned extrinsic + let unsigned_tx = quantus_client.client().tx().create_unsigned(&verify_tx).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to create unsigned tx: {}", e)) + })?; + + let mut tx_progress = unsigned_tx + .submit_and_watch() + .await + .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to submit tx: {}", e)))?; + + while let Some(Ok(status)) = tx_progress.next().await { + match status { + TxStatus::InBestBlock(tx_in_block) => { + let block_hash = tx_in_block.block_hash(); + let tx_hash = tx_in_block.extrinsic_hash(); + + // Get all events from the block + let block = quantus_client.client().blocks().at(block_hash).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) + })?; + + let events = block.events().await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get events: {}", e)) + })?; + + // Find our extrinsic index + let extrinsics = block.extrinsics().await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get extrinsics: {}", e)) + })?; + + let our_ext_idx = extrinsics + .iter() + .enumerate() + .find(|(_, ext)| ext.hash() == tx_hash) + .map(|(idx, _)| idx as u32); + + // Collect NativeTransferred events for our extrinsic + let mut transfer_events = Vec::new(); + let mut found_proof_verified = false; + + log_verbose!(" Events for our extrinsic (idx={:?}):", our_ext_idx); + for event_result in events.iter() { + let event = event_result.map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to decode event: {}", + e + )) + })?; + + if let subxt::events::Phase::ApplyExtrinsic(ext_idx) = event.phase() { + if Some(ext_idx) == our_ext_idx { + // Log all events for our extrinsic + log_print!( + " Event: {}::{}", + event.pallet_name(), + event.variant_name() + ); + + // Decode ExtrinsicFailed to get the specific error + if let Ok(Some(ExtrinsicFailed { dispatch_error, .. })) = + event.as_event::() + { + let metadata = quantus_client.client().metadata(); + let error_msg = format_dispatch_error(&dispatch_error, &metadata); + log_print!(" DispatchError: {}", error_msg); + } + + if let Ok(Some(_)) = event.as_event::() + { + found_proof_verified = true; + } + if let Ok(Some(transfer)) = + event.as_event::() + { + transfer_events.push(transfer); + } + } + } + } + + if found_proof_verified { + // Log the minted amounts from transfer events + log_print!(" Tokens minted (from NativeTransferred events):"); + for (idx, transfer) in transfer_events.iter().enumerate() { + let to_hex = hex::encode(transfer.to.0); + log_print!( + " [{}] {} -> {} planck ({})", + idx, + to_hex, + transfer.amount, + format_balance(transfer.amount) + ); + } + return Ok((block_hash, transfer_events)); + } else { + return Err(crate::error::QuantusError::Generic( + "Proof verification failed - no ProofVerified event".to_string(), + )); + } + }, + TxStatus::Error { message } | TxStatus::Invalid { message } => { + return Err(crate::error::QuantusError::Generic(format!( + "Transaction failed: {}", + message + ))); + }, + _ => continue, + } + } + + Err(crate::error::QuantusError::Generic("Transaction stream ended unexpectedly".to_string())) +} + +/// Dry run - show what would happen without executing +fn run_multiround_dry_run( + mnemonic: &str, + num_proofs: usize, + rounds: usize, + amount: u128, + wallet_address: &str, +) -> crate::error::Result<()> { + use colored::Colorize; + + log_print!(""); + log_print!("{}", "=== DRY RUN MODE ===".bright_yellow()); + log_print!("No transactions will be executed."); + log_print!(""); + + for round in 1..=rounds { + let is_final = round == rounds; + let round_amount = calculate_round_amount(amount, round); + + log_print!(""); + log_print!("{}", format!("Round {}", round).bright_cyan()); + log_print!(" Amount: {} ({})", round_amount, format_balance(round_amount)); + log_print!(""); + + log_print!(" Wormhole addresses (to be funded):"); + for i in 1..=num_proofs { + let secret = derive_wormhole_secret(mnemonic, round, i)?; + let address = sp_core::crypto::AccountId32::new(secret.address) + .to_ss58check_with_version(sp_core::crypto::Ss58AddressFormat::custom(189)); + log_print!(" [{}] {}", i, address); + log_verbose!(" secret: 0x{}", hex::encode(secret.secret)); + } + + log_print!(""); + log_print!(" Exit accounts:"); + if is_final { + log_print!(" All proofs exit to wallet: {}", wallet_address); + } else { + for i in 1..=num_proofs { + let next_secret = derive_wormhole_secret(mnemonic, round + 1, i)?; + let address = sp_core::crypto::AccountId32::new(next_secret.address) + .to_ss58check_with_version(sp_core::crypto::Ss58AddressFormat::custom(189)); + log_print!(" [{}] {} (round {} wormhole)", i, address, round + 1); + } + } + } + + log_print!(""); + log_print!("{}", "=== END DRY RUN ===".bright_yellow()); + log_print!(""); + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -1059,7 +2125,7 @@ mod tests { }; use qp_wormhole_prover::WormholeProver; use qp_wormhole_test_helpers::TestInputs; - use qp_wormhole_verifier::WormholeVerifier; + use tempfile::NamedTempFile; /// Helper to get a standard circuit config for tests @@ -1191,8 +2257,8 @@ mod tests { let output_medium = compute_output_amount(input_medium, VOLUME_FEE_BPS); assert_eq!(output_medium, 9990); assert!( - (output_medium as u64) * 10000 <= - (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) + (output_medium as u64) * 10000 + <= (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) ); // Large amounts near u32::MAX @@ -1275,10 +2341,10 @@ mod tests { // Verify fee constraint is satisfied in test inputs let input_amount = inputs.private.input_amount; - let output_amount = inputs.public.output_amount; + let output_amount = inputs.public.output_amount_1 + inputs.public.output_amount_2; assert!( - (output_amount as u64) * 10000 <= - (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), + (output_amount as u64) * 10000 + <= (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), "Test inputs violate fee constraint" ); @@ -1293,10 +2359,12 @@ mod tests { PublicCircuitInputs::try_from(&proof).expect("Failed to parse public inputs"); assert_eq!(parsed_public_inputs.asset_id, inputs.public.asset_id); - assert_eq!(parsed_public_inputs.output_amount, inputs.public.output_amount); + assert_eq!(parsed_public_inputs.output_amount_1, inputs.public.output_amount_1); + assert_eq!(parsed_public_inputs.output_amount_2, inputs.public.output_amount_2); assert_eq!(parsed_public_inputs.volume_fee_bps, inputs.public.volume_fee_bps); assert_eq!(parsed_public_inputs.nullifier, inputs.public.nullifier); - assert_eq!(parsed_public_inputs.exit_account, inputs.public.exit_account); + assert_eq!(parsed_public_inputs.exit_account_1, inputs.public.exit_account_1); + assert_eq!(parsed_public_inputs.exit_account_2, inputs.public.exit_account_2); assert_eq!(parsed_public_inputs.block_hash, inputs.public.block_hash); assert_eq!(parsed_public_inputs.parent_hash, inputs.public.parent_hash); assert_eq!(parsed_public_inputs.block_number, inputs.public.block_number); @@ -1531,7 +2599,6 @@ mod tests { /// Parse and display the contents of a proof file for debugging async fn parse_proof_file(proof_file: String, aggregated: bool) -> crate::error::Result<()> { - use qp_wormhole_aggregator::aggregator::WormholeProofAggregator; use std::path::Path; log_print!("Parsing proof file: {}", proof_file); @@ -1634,10 +2701,12 @@ async fn parse_proof_file(proof_file: String, aggregated: bool) -> crate::error: log_print!("\n=== Parsed Leaf Public Inputs ==="); log_print!("Asset ID: {}", pi.asset_id); - log_print!("Output Amount: {}", pi.output_amount); + log_print!("Output Amount 1: {}", pi.output_amount_1); + log_print!("Output Amount 2: {}", pi.output_amount_2); log_print!("Volume Fee BPS: {}", pi.volume_fee_bps); log_print!("Nullifier: 0x{}", hex::encode(pi.nullifier.as_ref())); - log_print!("Exit Account: 0x{}", hex::encode(pi.exit_account.as_ref())); + log_print!("Exit Account 1: 0x{}", hex::encode(pi.exit_account_1.as_ref())); + log_print!("Exit Account 2: 0x{}", hex::encode(pi.exit_account_2.as_ref())); log_print!("Block Hash: 0x{}", hex::encode(pi.block_hash.as_ref())); log_print!("Parent Hash: 0x{}", hex::encode(pi.parent_hash.as_ref())); log_print!("Block Number: {}", pi.block_number); diff --git a/src/wallet/keystore.rs b/src/wallet/keystore.rs index aeed76b..a8a9b28 100644 --- a/src/wallet/keystore.rs +++ b/src/wallet/keystore.rs @@ -214,8 +214,8 @@ impl Keystore { // 3. Use password hash as AES-256 key (quantum-safe with 256-bit key) let hash_bytes = password_hash.hash.as_ref().unwrap().as_bytes(); - let aes_key = Key::::from_slice(&hash_bytes[..32]); - let cipher = Aes256Gcm::new(aes_key); + let aes_key = Key::::from(<[u8; 32]>::try_from(&hash_bytes[..32]).unwrap()); + let cipher = Aes256Gcm::new(&aes_key); // 4. Generate nonce and encrypt the wallet data let nonce = Aes256Gcm::generate_nonce(&mut AesOsRng); @@ -255,13 +255,13 @@ impl Keystore { // 2. Derive AES key from verified password hash let hash_bytes = password_hash.hash.as_ref().unwrap().as_bytes(); - let aes_key = Key::::from_slice(&hash_bytes[..32]); - let cipher = Aes256Gcm::new(aes_key); + let aes_key = Key::::from(<[u8; 32]>::try_from(&hash_bytes[..32]).unwrap()); + let cipher = Aes256Gcm::new(&aes_key); // 3. Decrypt the data - let nonce = Nonce::from_slice(&encrypted.aes_nonce); + let nonce = Nonce::from(<[u8; 12]>::try_from(&encrypted.aes_nonce[..]).unwrap()); let decrypted_data = cipher - .decrypt(nonce, encrypted.encrypted_data.as_ref()) + .decrypt(&nonce, encrypted.encrypted_data.as_ref()) .map_err(|_| WalletError::Decryption)?; // 4. Deserialize the wallet data diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index f92ec96..3daa1c0 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -10,7 +10,7 @@ pub mod password; use crate::error::{Result, WalletError}; pub use keystore::{Keystore, QuantumKeyPair, WalletData}; -use qp_rusty_crystals_hdwallet::{generate_mnemonic, HDLattice}; +use qp_rusty_crystals_hdwallet::{derive_key_from_mnemonic, generate_mnemonic, SensitiveBytes32}; use rand::{rng, RngCore}; use serde::{Deserialize, Serialize}; use sp_runtime::traits::IdentifyAccount; @@ -69,11 +69,9 @@ impl WalletManager { // Generate a new Dilithium keypair using derivation path let mut seed = [0u8; 32]; rng().fill_bytes(&mut seed); - let mnemonic = generate_mnemonic(24, seed).map_err(|_| WalletError::KeyGeneration)?; - let lattice = - HDLattice::from_mnemonic(&mnemonic, None).expect("Failed to generate lattice"); - let dilithium_keypair = lattice - .generate_derived_keys(derivation_path) + let sensitive_seed = SensitiveBytes32::from(&mut seed); + let mnemonic = generate_mnemonic(sensitive_seed).map_err(|_| WalletError::KeyGeneration)?; + let dilithium_keypair = derive_key_from_mnemonic(&mnemonic, None, derivation_path) .map_err(|_| WalletError::KeyGeneration)?; let quantum_keypair = QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); @@ -219,13 +217,14 @@ impl WalletManager { return Err(WalletError::AlreadyExists.into()); } - // Generate new mnemonic and use master seed directly + // Generate new mnemonic and use master seed directly (no derivation path) let mut seed = [0u8; 32]; rng().fill_bytes(&mut seed); - let mnemonic = generate_mnemonic(24, seed).map_err(|_| WalletError::KeyGeneration)?; - let lattice = - HDLattice::from_mnemonic(&mnemonic, None).map_err(|_| WalletError::KeyGeneration)?; - let dilithium_keypair = lattice.generate_keys(); + let sensitive_seed = SensitiveBytes32::from(&mut seed); + let mnemonic = generate_mnemonic(sensitive_seed).map_err(|_| WalletError::KeyGeneration)?; + // For "no derivation" mode, we use the root path m/ + let dilithium_keypair = derive_key_from_mnemonic(&mnemonic, None, "m/44'/189189'/0'") + .map_err(|_| WalletError::KeyGeneration)?; let quantum_keypair = QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); // Create wallet data @@ -272,10 +271,9 @@ impl WalletManager { return Err(WalletError::AlreadyExists.into()); } - // Use mnemonic to generate master seed directly - let lattice = - HDLattice::from_mnemonic(mnemonic, None).map_err(|_| WalletError::InvalidMnemonic)?; - let dilithium_keypair = lattice.generate_keys(); + // Use mnemonic to generate keys directly (no derivation path) + let dilithium_keypair = derive_key_from_mnemonic(mnemonic, None, "m/44'/189189'/0'") + .map_err(|_| WalletError::InvalidMnemonic)?; let quantum_keypair = QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); // Create wallet data @@ -325,11 +323,8 @@ impl WalletManager { } // Validate and import from mnemonic using derivation path - let lattice = - HDLattice::from_mnemonic(mnemonic, None).map_err(|_| WalletError::InvalidMnemonic)?; - let dilithium_keypair = lattice - .generate_derived_keys(derivation_path) - .map_err(|_| WalletError::KeyGeneration)?; + let dilithium_keypair = derive_key_from_mnemonic(mnemonic, None, derivation_path) + .map_err(|_| WalletError::InvalidMnemonic)?; let quantum_keypair = QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); // Create wallet data From c76f39c87ae93c8d4e87b7feae0803ec927b7172 Mon Sep 17 00:00:00 2001 From: illuzen Date: Thu, 12 Feb 2026 03:40:48 +0800 Subject: [PATCH 04/26] remove on chain verification command, add verification flag to parser command --- src/cli/wormhole.rs | 335 ++++++++++++++++++++++---------------------- 1 file changed, 166 insertions(+), 169 deletions(-) diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 7774cf4..6a495af 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -125,6 +125,64 @@ pub fn format_balance(amount: u128) -> String { format!("{}.{:02} DEV", whole, frac) } +/// Randomly partition a total amount into n parts. +/// Each part will be at least `min_per_part` and the sum equals `total`. +/// Returns amounts aligned to SCALE_DOWN_FACTOR for clean quantization. +pub fn random_partition(total: u128, n: usize, min_per_part: u128) -> Vec { + use rand::Rng; + + if n == 0 { + return vec![]; + } + if n == 1 { + return vec![total]; + } + + // Ensure minimum is achievable + let min_total = min_per_part * n as u128; + if total < min_total { + // Fall back to equal distribution if total is too small + let per_part = total / n as u128; + let remainder = total % n as u128; + let mut parts: Vec = vec![per_part; n]; + // Add remainder to last part + parts[n - 1] += remainder; + return parts; + } + + // Amount available for random distribution after ensuring minimums + let distributable = total - min_total; + + // Generate n-1 random cut points in [0, distributable] + let mut rng = rand::rng(); + let mut cuts: Vec = (0..n - 1).map(|_| rng.random_range(0..=distributable)).collect(); + cuts.sort(); + + // Convert cuts to amounts + let mut parts = Vec::with_capacity(n); + let mut prev = 0u128; + for cut in cuts { + parts.push(min_per_part + (cut - prev)); + prev = cut; + } + parts.push(min_per_part + (distributable - prev)); + + // Align each part to SCALE_DOWN_FACTOR for clean quantization + let alignment = SCALE_DOWN_FACTOR; + let mut aligned_parts: Vec = parts.iter().map(|&p| (p / alignment) * alignment).collect(); + + // Adjust to ensure sum equals total (add remainder to random part) + let aligned_sum: u128 = aligned_parts.iter().sum(); + let diff = total as i128 - aligned_sum as i128; + if diff != 0 { + // Add/subtract difference from a random part + let idx = rng.random_range(0..n); + aligned_parts[idx] = (aligned_parts[idx] as i128 + diff) as u128; + } + + aligned_parts +} + /// Result of checking proof verification events pub struct VerificationResult { pub success: bool, @@ -335,12 +393,6 @@ pub enum WormholeCommands { #[arg(short, long, default_value = "proof.hex")] output: String, }, - /// Verify a single wormhole proof on-chain - Verify { - /// Path to the proof file (hex-encoded) - #[arg(short, long, default_value = "proof.hex")] - proof: String, - }, /// Aggregate multiple wormhole proofs into a single proof Aggregate { /// Input proof files (hex-encoded) @@ -375,6 +427,10 @@ pub enum WormholeCommands { /// Parse as aggregated proof (default: false, parses as leaf proof) #[arg(long)] aggregated: bool, + + /// Verify the proof cryptographically (local verification, not on-chain) + #[arg(long)] + verify: bool, }, /// Run a multi-round wormhole test: wallet -> wormhole -> ... -> wallet Multiround { @@ -445,15 +501,14 @@ pub async fn handle_wormhole_command( ) .await }, - WormholeCommands::Verify { proof } => verify_proof(proof, node_url).await, WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => { aggregate_proofs(proofs, output, depth, branching_factor).await }, WormholeCommands::VerifyAggregated { proof } => { verify_aggregated_proof(proof, node_url).await }, - WormholeCommands::ParseProof { proof, aggregated } => { - parse_proof_file(proof, aggregated).await + WormholeCommands::ParseProof { proof, aggregated, verify } => { + parse_proof_file(proof, aggregated, verify).await }, WormholeCommands::Multiround { num_proofs, @@ -1040,116 +1095,6 @@ async fn verify_aggregated_proof(proof_file: String, node_url: &str) -> crate::e Err(crate::error::QuantusError::Generic("Transaction stream ended unexpectedly".to_string())) } -async fn verify_proof(proof_file: String, node_url: &str) -> crate::error::Result<()> { - use subxt::tx::TxStatus; - - log_print!("Verifying wormhole proof on-chain..."); - - // Read proof from file - let proof_hex = std::fs::read_to_string(&proof_file).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to read proof file: {}", e)) - })?; - - let proof_bytes = hex::decode(proof_hex.trim()) - .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to decode hex: {}", e)))?; - - log_verbose!("Proof size: {} bytes", proof_bytes.len()); - - // Connect to node - let quantus_client = QuantusClient::new(node_url) - .await - .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to connect: {}", e)))?; - - log_verbose!("Connected to node"); - - // Create the verify transaction payload - let verify_tx = quantus_node::api::tx().wormhole().verify_wormhole_proof(proof_bytes); - - log_verbose!("Submitting unsigned verification transaction..."); - - // Submit as unsigned extrinsic - let unsigned_tx = quantus_client.client().tx().create_unsigned(&verify_tx).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to create unsigned tx: {}", e)) - })?; - - let mut tx_progress = unsigned_tx - .submit_and_watch() - .await - .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to submit tx: {}", e)))?; - - // Wait for transaction inclusion and verify events - while let Some(Ok(status)) = tx_progress.next().await { - log_verbose!("Transaction status: {:?}", status); - match status { - TxStatus::InBestBlock(tx_in_block) => { - let block_hash = tx_in_block.block_hash(); - let tx_hash = tx_in_block.extrinsic_hash(); - - // Check for ProofVerified event - let result = check_proof_verification_events( - quantus_client.client(), - &block_hash, - &tx_hash, - crate::log::is_verbose(), - ) - .await?; - - if result.success { - log_success!("Proof verified successfully on-chain!"); - if let Some(amount) = result.exit_amount { - log_success!("Exit amount: {}", format_balance(amount)); - } - log_verbose!("Included in block: {:?}", block_hash); - return Ok(()); - } else { - let error_msg = result.error_message.unwrap_or_else(|| { - "Proof verification failed - no ProofVerified event found".to_string() - }); - log_error!("❌ {}", error_msg); - return Err(crate::error::QuantusError::Generic(error_msg)); - } - }, - TxStatus::InFinalizedBlock(tx_in_block) => { - let block_hash = tx_in_block.block_hash(); - let tx_hash = tx_in_block.extrinsic_hash(); - - // Check for ProofVerified event - let result = check_proof_verification_events( - quantus_client.client(), - &block_hash, - &tx_hash, - crate::log::is_verbose(), - ) - .await?; - - if result.success { - log_success!("Proof verified successfully on-chain!"); - if let Some(amount) = result.exit_amount { - log_success!("Exit amount: {}", format_balance(amount)); - } - log_verbose!("Finalized in block: {:?}", block_hash); - return Ok(()); - } else { - let error_msg = result.error_message.unwrap_or_else(|| { - "Proof verification failed - no ProofVerified event found".to_string() - }); - log_error!("❌ {}", error_msg); - return Err(crate::error::QuantusError::Generic(error_msg)); - } - }, - TxStatus::Error { message } | TxStatus::Invalid { message } => { - return Err(crate::error::QuantusError::Generic(format!( - "Transaction failed: {}", - message - ))); - }, - _ => continue, - } - } - - Err(crate::error::QuantusError::Generic("Transaction stream ended unexpectedly".to_string())) -} - // ============================================================================ // Multi-round wormhole flow implementation // ============================================================================ @@ -1304,7 +1249,12 @@ async fn run_multiround( log_print!("{}", "Configuration:".bright_cyan()); log_print!(" Wallet: {}", wallet_name); log_print!(" Wallet address: {}", wallet_address); - log_print!(" Initial amount: {} ({})", amount, format_balance(amount)); + log_print!( + " Total amount: {} ({}) - randomly partitioned across {} proofs", + amount, + format_balance(amount), + num_proofs + ); log_print!(" Proofs per round: {}", num_proofs); log_print!(" Rounds: {}", rounds); log_print!( @@ -1413,6 +1363,15 @@ async fn run_multiround( if round == 1 { log_print!("{}", "Step 1: Sending wormhole transfers from wallet...".bright_yellow()); + // Randomly partition the total amount among proofs + // Minimum 1 DEV per proof to ensure meaningful amounts + let min_per_proof = SCALE_DOWN_FACTOR; // 0.01 DEV (minimum quantizable amount) + let partition_amounts = random_partition(amount, num_proofs, min_per_proof); + log_print!(" Random partition of {} ({}):", amount, format_balance(amount)); + for (i, &amt) in partition_amounts.iter().enumerate() { + log_print!(" Proof {}: {} ({})", i + 1, amt, format_balance(amt)); + } + let pb = ProgressBar::new(num_proofs as u64); pb.set_style( ProgressStyle::default_bar() @@ -1426,11 +1385,12 @@ async fn run_multiround( pb.set_message(format!("Transfer {}/{}", i + 1, num_proofs)); let wormhole_address = SubxtAccountId(secret.address); + let transfer_amount = partition_amounts[i]; // Submit transfer let transfer_tx = quantus_node::api::tx().wormhole().transfer_native( subxt::ext::subxt_core::utils::MultiAddress::Id(wormhole_address.clone()), - amount, + transfer_amount, ); let quantum_keypair = QuantumKeyPair { @@ -1477,7 +1437,7 @@ async fn run_multiround( current_transfers.push(TransferInfo { block_hash, transfer_count: event.transfer_count, - amount, + amount: transfer_amount, wormhole_address, funding_account: SubxtAccountId(funding_account_bytes.into()), }); @@ -2083,7 +2043,17 @@ fn run_multiround_dry_run( log_print!(""); log_print!("{}", format!("Round {}", round).bright_cyan()); - log_print!(" Amount: {} ({})", round_amount, format_balance(round_amount)); + log_print!(" Total amount: {} ({})", round_amount, format_balance(round_amount)); + + // Show sample random partition for round 1 + if round == 1 { + let min_per_proof = SCALE_DOWN_FACTOR; // 0.01 DEV (minimum quantizable amount) + let partition = random_partition(amount, num_proofs, min_per_proof); + log_print!(" Sample random partition (actual partition will differ):"); + for (i, &amt) in partition.iter().enumerate() { + log_print!(" Proof {}: {} ({})", i + 1, amt, format_balance(amt)); + } + } log_print!(""); log_print!(" Wormhole addresses (to be funded):"); @@ -2598,8 +2568,12 @@ mod tests { } /// Parse and display the contents of a proof file for debugging -async fn parse_proof_file(proof_file: String, aggregated: bool) -> crate::error::Result<()> { - use std::path::Path; +async fn parse_proof_file( + proof_file: String, + aggregated: bool, + verify: bool, +) -> crate::error::Result<()> { + use qp_wormhole_verifier::WormholeVerifier; log_print!("Parsing proof file: {}", proof_file); @@ -2610,45 +2584,32 @@ async fn parse_proof_file(proof_file: String, aggregated: bool) -> crate::error: log_print!("Proof size: {} bytes", proof_bytes.len()); if aggregated { - use plonky2::{ - plonk::circuit_data::CommonCircuitData, util::serialization::DefaultGateSerializer, - }; + // Load aggregated verifier + let verifier_bytes = include_bytes!("../../generated-bins/aggregated_verifier.bin"); + let common_bytes = include_bytes!("../../generated-bins/aggregated_common.bin"); + let verifier = + WormholeVerifier::new_from_bytes(verifier_bytes, common_bytes).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) + })?; - // Load aggregated circuit common data - let bins_dir = Path::new("generated-bins"); - let common_bytes = std::fs::read(bins_dir.join("aggregated_common.bin")).map_err(|e| { + // Deserialize proof using verifier's types + let proof = qp_wormhole_verifier::ProofWithPublicInputs::< + qp_wormhole_verifier::F, + qp_wormhole_verifier::C, + { qp_wormhole_verifier::D }, + >::from_bytes(proof_bytes.clone(), &verifier.circuit_data.common) + .map_err(|e| { crate::error::QuantusError::Generic(format!( - "Failed to read aggregated_common.bin: {}", + "Failed to deserialize aggregated proof: {:?}", e )) })?; - let gate_serializer = DefaultGateSerializer; - let common_data = CommonCircuitData::::from_bytes(common_bytes, &gate_serializer) - .map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to deserialize aggregated common data: {:?}", - e - )) - })?; - - let proof = ProofWithPublicInputs::::from_bytes(proof_bytes.clone(), &common_data) - .map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to deserialize aggregated proof: {:?}", - e - )) - })?; - log_print!("\nPublic inputs count: {}", proof.public_inputs.len()); - log_print!("\nPublic inputs (raw field elements):"); - for (i, pi) in proof.public_inputs.iter().enumerate() { - use plonky2::field::types::PrimeField64; - log_print!(" [{}] = {}", i, pi.to_canonical_u64()); - } + log_verbose!("\nPublic inputs count: {}", proof.public_inputs.len()); // Try to parse as aggregated - match AggregatedPublicCircuitInputs::try_from_slice(&proof.public_inputs) { + match qp_wormhole_verifier::parse_aggregated_public_inputs(&proof) { Ok(agg_inputs) => { log_print!("\n=== Parsed Aggregated Public Inputs ==="); log_print!("Asset ID: {}", agg_inputs.asset_id); @@ -2676,26 +2637,45 @@ async fn parse_proof_file(proof_file: String, aggregated: bool) -> crate::error: log_print!("Failed to parse as aggregated inputs: {}", e); }, } + + // Verify if requested + if verify { + log_print!("\n=== Verifying Proof ==="); + match verifier.verify(proof) { + Ok(()) => { + log_success!("Proof verification PASSED"); + }, + Err(e) => { + log_error!("Proof verification FAILED: {}", e); + return Err(crate::error::QuantusError::Generic(format!( + "Proof verification failed: {}", + e + ))); + }, + } + } } else { - // Parse as leaf proof - let bins_dir = Path::new("generated-bins"); - let prover = qp_wormhole_prover::WormholeProver::new_from_files( - &bins_dir.join("prover.bin"), - &bins_dir.join("common.bin"), - ) + // Load leaf verifier + let verifier_bytes = include_bytes!("../../generated-bins/verifier.bin"); + let common_bytes = include_bytes!("../../generated-bins/common.bin"); + let verifier = + WormholeVerifier::new_from_bytes(verifier_bytes, common_bytes).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) + })?; + + // Deserialize proof using verifier's types + let proof = qp_wormhole_verifier::ProofWithPublicInputs::< + qp_wormhole_verifier::F, + qp_wormhole_verifier::C, + { qp_wormhole_verifier::D }, + >::from_bytes(proof_bytes, &verifier.circuit_data.common) .map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load prover: {}", e)) + crate::error::QuantusError::Generic(format!("Failed to deserialize proof: {:?}", e)) })?; - let common_data = &prover.circuit_data.common; - let proof = ProofWithPublicInputs::::from_bytes(proof_bytes, common_data) - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to deserialize proof: {}", e)) - })?; - log_print!("\nPublic inputs count: {}", proof.public_inputs.len()); - let pi = PublicCircuitInputs::try_from(&proof).map_err(|e| { + let pi = qp_wormhole_verifier::parse_public_inputs(&proof).map_err(|e| { crate::error::QuantusError::Generic(format!("Failed to parse public inputs: {}", e)) })?; @@ -2710,6 +2690,23 @@ async fn parse_proof_file(proof_file: String, aggregated: bool) -> crate::error: log_print!("Block Hash: 0x{}", hex::encode(pi.block_hash.as_ref())); log_print!("Parent Hash: 0x{}", hex::encode(pi.parent_hash.as_ref())); log_print!("Block Number: {}", pi.block_number); + + // Verify if requested + if verify { + log_print!("\n=== Verifying Proof ==="); + match verifier.verify(proof) { + Ok(()) => { + log_success!("Proof verification PASSED"); + }, + Err(e) => { + log_error!("Proof verification FAILED: {}", e); + return Err(crate::error::QuantusError::Generic(format!( + "Proof verification failed: {}", + e + ))); + }, + } + } } Ok(()) From 99494778a257c299666d402285eeee14850fbd5c Mon Sep 17 00:00:00 2001 From: illuzen Date: Thu, 12 Feb 2026 03:47:06 +0800 Subject: [PATCH 05/26] build circuits command + fmt --- src/cli/mod.rs | 145 +++++++++++++++++++++++++++++++++++++++++--- src/cli/wormhole.rs | 44 ++++++-------- 2 files changed, 158 insertions(+), 31 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 6d9a1cd..94c4ff1 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -238,6 +238,21 @@ pub enum Commands { pub enum DeveloperCommands { /// Create standard test wallets (crystal_alice, crystal_bob, crystal_charlie) CreateTestWallets, + + /// Build wormhole circuit binaries and copy to CLI and chain directories + BuildCircuits { + /// Path to qp-zk-circuits repository (default: ../qp-zk-circuits) + #[arg(long, default_value = "../qp-zk-circuits")] + circuits_path: String, + + /// Path to chain repository (default: ../chain) + #[arg(long, default_value = "../chain")] + chain_path: String, + + /// Skip copying to chain directory + #[arg(long)] + skip_chain: bool, + }, } /// Execute a CLI command @@ -326,13 +341,7 @@ pub async fn execute_command( log_print!("💰 Balance: {}", formatted_balance); Ok(()) }, - Commands::Developer(dev_cmd) => match dev_cmd { - DeveloperCommands::CreateTestWallets => { - let _ = crate::cli::handle_developer_command(DeveloperCommands::CreateTestWallets) - .await; - Ok(()) - }, - }, + Commands::Developer(dev_cmd) => handle_developer_command(dev_cmd).await, Commands::Events { block, block_hash, latest: _, finalized, pallet, raw, no_decode } => events::handle_events_command( block, block_hash, finalized, pallet, raw, !no_decode, node_url, @@ -467,7 +476,129 @@ pub async fn handle_developer_command(command: DeveloperCommands) -> crate::erro Ok(()) }, + DeveloperCommands::BuildCircuits { circuits_path, chain_path, skip_chain } => + build_wormhole_circuits(&circuits_path, &chain_path, skip_chain).await, + } +} + +/// Build wormhole circuit binaries and copy them to the appropriate locations +async fn build_wormhole_circuits( + circuits_path: &str, + chain_path: &str, + skip_chain: bool, +) -> crate::error::Result<()> { + use std::{path::Path, process::Command}; + + log_print!("🔧 {} Building wormhole circuit binaries...", "DEVELOPER".bright_magenta().bold()); + log_print!(""); + + let circuits_dir = Path::new(circuits_path); + let chain_dir = Path::new(chain_path); + + // Verify circuits directory exists + if !circuits_dir.exists() { + return Err(crate::error::QuantusError::Generic(format!( + "Circuits directory not found: {}", + circuits_path + ))); } + + // Step 1: Build the circuit builder + log_print!("📦 Step 1: Building circuit builder..."); + let build_output = Command::new("cargo") + .args(["build", "--release", "-p", "qp-wormhole-circuit-builder"]) + .current_dir(circuits_dir) + .output() + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to run cargo build: {}", e)) + })?; + + if !build_output.status.success() { + let stderr = String::from_utf8_lossy(&build_output.stderr); + return Err(crate::error::QuantusError::Generic(format!( + "Circuit builder compilation failed:\n{}", + stderr + ))); + } + log_success!(" Circuit builder compiled successfully"); + + // Step 2: Run the circuit builder + log_print!("⚡ Step 2: Running circuit builder (this may take a while)..."); + let builder_path = circuits_dir.join("target/release/qp-wormhole-circuit-builder"); + let run_output = + Command::new(&builder_path).current_dir(circuits_dir).output().map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to run circuit builder: {}", e)) + })?; + + if !run_output.status.success() { + let stderr = String::from_utf8_lossy(&run_output.stderr); + return Err(crate::error::QuantusError::Generic(format!( + "Circuit builder failed:\n{}", + stderr + ))); + } + log_success!(" Circuit binaries generated"); + + // Step 3: Copy binaries to CLI directory + log_print!("📋 Step 3: Copying binaries to CLI..."); + let source_bins = circuits_dir.join("generated-bins"); + let cli_bins = Path::new("generated-bins"); + + let bin_files = [ + "common.bin", + "verifier.bin", + "prover.bin", + "aggregated_common.bin", + "aggregated_verifier.bin", + ]; + + for file in &bin_files { + let src = source_bins.join(file); + let dst = cli_bins.join(file); + std::fs::copy(&src, &dst).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to copy {} to CLI: {}", file, e)) + })?; + log_verbose!(" Copied {} to CLI", file); + } + log_success!(" Binaries copied to CLI"); + + // Step 4: Copy binaries to chain directory (if not skipped) + if !skip_chain { + log_print!("📋 Step 4: Copying binaries to chain..."); + + if !chain_dir.exists() { + log_error!(" Chain directory not found: {} (use --skip-chain to skip)", chain_path); + } else { + let chain_bins = chain_dir.join("pallets/wormhole"); + for file in &bin_files { + let src = source_bins.join(file); + let dst = chain_bins.join(file); + std::fs::copy(&src, &dst).map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to copy {} to chain: {}", + file, e + )) + })?; + log_verbose!(" Copied {} to chain", file); + } + log_success!(" Binaries copied to chain"); + } + } else { + log_print!("⏭️ Step 4: Skipping chain copy (--skip-chain)"); + } + + log_print!(""); + log_success!("🎉 Circuit build complete!"); + log_print!(""); + log_print!("💡 {} Next steps:", "TIP".bright_blue().bold()); + log_print!(" 1. Rebuild the CLI: cargo build --release"); + if !skip_chain { + log_print!(" 2. Rebuild the chain: cd {} && cargo build --release", chain_path); + log_print!(" 3. Restart the chain node with the new binary"); + } + log_print!(""); + + Ok(()) } /// Handle compatibility check command diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 6a495af..a2a47ea 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -3,8 +3,10 @@ use crate::{ client::{ChainConfig, QuantusClient}, quantus_subxt::{self as quantus_node, api::wormhole}, }, - cli::common::{submit_transaction, ExecutionMode}, - cli::send::get_balance, + cli::{ + common::{submit_transaction, ExecutionMode}, + send::get_balance, + }, log_error, log_print, log_success, log_verbose, wallet::{password, QuantumKeyPair, WalletManager}, }; @@ -477,9 +479,8 @@ pub async fn handle_wormhole_command( node_url: &str, ) -> crate::error::Result<()> { match command { - WormholeCommands::Transfer { secret, amount, from, password, password_file } => { - submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await - }, + WormholeCommands::Transfer { secret, amount, from, password, password_file } => + submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await, WormholeCommands::Generate { secret, amount, @@ -488,7 +489,7 @@ pub async fn handle_wormhole_command( transfer_count, funding_account, output, - } => { + } => generate_proof( secret, amount, @@ -499,17 +500,13 @@ pub async fn handle_wormhole_command( output, node_url, ) - .await - }, - WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => { - aggregate_proofs(proofs, output, depth, branching_factor).await - }, - WormholeCommands::VerifyAggregated { proof } => { - verify_aggregated_proof(proof, node_url).await - }, - WormholeCommands::ParseProof { proof, aggregated, verify } => { - parse_proof_file(proof, aggregated, verify).await - }, + .await, + WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => + aggregate_proofs(proofs, output, depth, branching_factor).await, + WormholeCommands::VerifyAggregated { proof } => + verify_aggregated_proof(proof, node_url).await, + WormholeCommands::ParseProof { proof, aggregated, verify } => + parse_proof_file(proof, aggregated, verify).await, WormholeCommands::Multiround { num_proofs, rounds, @@ -520,7 +517,7 @@ pub async fn handle_wormhole_command( keep_files, output_dir, dry_run, - } => { + } => run_multiround( num_proofs, rounds, @@ -533,8 +530,7 @@ pub async fn handle_wormhole_command( dry_run, node_url, ) - .await - }, + .await, } } @@ -2227,8 +2223,8 @@ mod tests { let output_medium = compute_output_amount(input_medium, VOLUME_FEE_BPS); assert_eq!(output_medium, 9990); assert!( - (output_medium as u64) * 10000 - <= (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) + (output_medium as u64) * 10000 <= + (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) ); // Large amounts near u32::MAX @@ -2313,8 +2309,8 @@ mod tests { let input_amount = inputs.private.input_amount; let output_amount = inputs.public.output_amount_1 + inputs.public.output_amount_2; assert!( - (output_amount as u64) * 10000 - <= (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), + (output_amount as u64) * 10000 <= + (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), "Test inputs violate fee constraint" ); From b704daa771e8d5b3f41386834902d562112aea2e Mon Sep 17 00:00:00 2001 From: illuzen Date: Thu, 12 Feb 2026 04:53:54 +0800 Subject: [PATCH 06/26] random partition multiround --- src/cli/wormhole.rs | 262 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 214 insertions(+), 48 deletions(-) diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index a2a47ea..7e40c0b 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -169,20 +169,154 @@ pub fn random_partition(total: u128, n: usize, min_per_part: u128) -> Vec } parts.push(min_per_part + (distributable - prev)); - // Align each part to SCALE_DOWN_FACTOR for clean quantization - let alignment = SCALE_DOWN_FACTOR; - let mut aligned_parts: Vec = parts.iter().map(|&p| (p / alignment) * alignment).collect(); - - // Adjust to ensure sum equals total (add remainder to random part) - let aligned_sum: u128 = aligned_parts.iter().sum(); - let diff = total as i128 - aligned_sum as i128; + // Note: Input 'total' is already in quantized units (e.g., 998 = 9.98 DEV). + // No further alignment is needed - just ensure the sum equals total. + let sum: u128 = parts.iter().sum(); + let diff = total as i128 - sum as i128; if diff != 0 { // Add/subtract difference from a random part let idx = rng.random_range(0..n); - aligned_parts[idx] = (aligned_parts[idx] as i128 + diff) as u128; + parts[idx] = (parts[idx] as i128 + diff) as u128; + } + + parts +} + +/// Output assignment for a single proof (supports dual outputs) +#[derive(Debug, Clone)] +pub struct ProofOutputAssignment { + /// Amount for output 1 (quantized, 2 decimal places) + pub output_amount_1: u32, + /// Exit account for output 1 + pub exit_account_1: [u8; 32], + /// Amount for output 2 (quantized, 0 if unused) + pub output_amount_2: u32, + /// Exit account for output 2 (all zeros if unused) + pub exit_account_2: [u8; 32], +} + +/// Compute random output assignments for a set of proofs. +/// +/// This takes the input amounts for each proof and randomly distributes the outputs +/// across the target exit accounts. Each proof can have up to 2 outputs. +/// +/// # Algorithm: +/// 1. Compute total output amount (sum of inputs after fee deduction) +/// 2. Randomly partition total output across all target addresses +/// 3. Greedily assign outputs to proofs, using dual outputs when necessary +/// +/// # Arguments +/// * `input_amounts` - The input amount for each proof (in planck, before fee) +/// * `target_accounts` - The exit accounts to distribute outputs to +/// * `fee_bps` - Fee in basis points +/// +/// # Returns +/// A vector of output assignments, one per proof +pub fn compute_random_output_assignments( + input_amounts: &[u128], + target_accounts: &[[u8; 32]], + fee_bps: u32, +) -> Vec { + use rand::seq::SliceRandom; + + let num_proofs = input_amounts.len(); + let num_targets = target_accounts.len(); + + if num_proofs == 0 || num_targets == 0 { + return vec![]; + } + + // Step 1: Compute output amounts per proof (after fee deduction) + let proof_outputs: Vec = input_amounts + .iter() + .map(|&input| { + let input_quantized = quantize_funding_amount(input).unwrap_or(0); + compute_output_amount(input_quantized, fee_bps) + }) + .collect(); + + let total_output: u64 = proof_outputs.iter().map(|&x| x as u64).sum(); + + // Step 2: Randomly partition total output across target accounts + // Minimum 1 quantized unit (0.01 DEV) per target to ensure all targets receive funds + let min_per_target = 1u128; + let target_amounts_u128 = random_partition(total_output as u128, num_targets, min_per_target); + let target_amounts: Vec = target_amounts_u128.iter().map(|&x| x as u32).collect(); + + // Step 3: Assign outputs to proofs using a greedy algorithm + // Each proof can have at most 2 outputs to different targets + // + // Strategy: For each proof, we try to split across two targets if possible + // to maximize mixing. We process targets in shuffled order. + + let mut rng = rand::rng(); + let mut assignments = Vec::with_capacity(num_proofs); + + // Shuffle target indices for random assignment order + let mut target_order: Vec = (0..num_targets).collect(); + target_order.shuffle(&mut rng); + + // Track remaining needs per target (in original index order) + let mut target_remaining: Vec = target_amounts.clone(); + + for &proof_output in proof_outputs.iter() { + let mut remaining = proof_output; + let mut output_1_amount = 0u32; + let mut output_1_account = [0u8; 32]; + let mut output_2_amount = 0u32; + let mut output_2_account = [0u8; 32]; + let mut outputs_assigned = 0; + + // Try to assign to targets in shuffled order + for &tidx in &target_order { + if remaining == 0 { + break; + } + if outputs_assigned >= 2 { + // Already have 2 outputs, add remainder to output_1 + output_1_amount += remaining; + remaining = 0; + break; + } + if target_remaining[tidx] == 0 { + continue; + } + + let assign = remaining.min(target_remaining[tidx]); + if assign == 0 { + continue; + } + + if outputs_assigned == 0 { + output_1_amount = assign; + output_1_account = target_accounts[tidx]; + } else { + output_2_amount = assign; + output_2_account = target_accounts[tidx]; + } + + remaining -= assign; + target_remaining[tidx] -= assign; + outputs_assigned += 1; + } + + // If we still have remaining (shouldn't happen normally), add to output_1 + if remaining > 0 { + output_1_amount += remaining; + } + + assignments.push(ProofOutputAssignment { + output_amount_1: output_1_amount, + exit_account_1: output_1_account, + output_amount_2: output_2_amount, + exit_account_2: output_2_account, + }); + + // Re-shuffle target order for next proof to increase mixing + target_order.shuffle(&mut rng); } - aligned_parts + assignments } /// Result of checking proof verification events @@ -479,8 +613,9 @@ pub async fn handle_wormhole_command( node_url: &str, ) -> crate::error::Result<()> { match command { - WormholeCommands::Transfer { secret, amount, from, password, password_file } => - submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await, + WormholeCommands::Transfer { secret, amount, from, password, password_file } => { + submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await + }, WormholeCommands::Generate { secret, amount, @@ -489,7 +624,7 @@ pub async fn handle_wormhole_command( transfer_count, funding_account, output, - } => + } => { generate_proof( secret, amount, @@ -500,13 +635,17 @@ pub async fn handle_wormhole_command( output, node_url, ) - .await, - WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => - aggregate_proofs(proofs, output, depth, branching_factor).await, - WormholeCommands::VerifyAggregated { proof } => - verify_aggregated_proof(proof, node_url).await, - WormholeCommands::ParseProof { proof, aggregated, verify } => - parse_proof_file(proof, aggregated, verify).await, + .await + }, + WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => { + aggregate_proofs(proofs, output, depth, branching_factor).await + }, + WormholeCommands::VerifyAggregated { proof } => { + verify_aggregated_proof(proof, node_url).await + }, + WormholeCommands::ParseProof { proof, aggregated, verify } => { + parse_proof_file(proof, aggregated, verify).await + }, WormholeCommands::Multiround { num_proofs, rounds, @@ -517,7 +656,7 @@ pub async fn handle_wormhole_command( keep_files, output_dir, dry_run, - } => + } => { run_multiround( num_proofs, rounds, @@ -530,7 +669,8 @@ pub async fn handle_wormhole_command( dry_run, node_url, ) - .await, + .await + }, } } @@ -1459,7 +1599,7 @@ async fn run_multiround( log_print!(" Found {} transfer(s) from previous round", current_transfers.len()); } - // Step 2: Generate proofs + // Step 2: Generate proofs with random output partitioning log_print!("{}", "Step 2: Generating proofs...".bright_yellow()); // All proofs in an aggregation batch must use the same block for storage proofs. @@ -1470,6 +1610,41 @@ async fn run_multiround( let proof_block_hash = proof_block.hash(); log_print!(" Using block {} for all proofs", hex::encode(proof_block_hash.0)); + // Collect input amounts and exit accounts for random assignment + let input_amounts: Vec = current_transfers.iter().map(|t| t.amount).collect(); + let exit_account_bytes: Vec<[u8; 32]> = exit_accounts.iter().map(|a| a.0).collect(); + + // Compute random output assignments (each proof can have 2 outputs) + let output_assignments = + compute_random_output_assignments(&input_amounts, &exit_account_bytes, VOLUME_FEE_BPS); + + // Log the random partition + log_print!(" Random output partition:"); + for (i, assignment) in output_assignments.iter().enumerate() { + let amt1_planck = (assignment.output_amount_1 as u128) * SCALE_DOWN_FACTOR; + if assignment.output_amount_2 > 0 { + let amt2_planck = (assignment.output_amount_2 as u128) * SCALE_DOWN_FACTOR; + log_print!( + " Proof {}: {} ({}) -> 0x{}..., {} ({}) -> 0x{}...", + i + 1, + assignment.output_amount_1, + format_balance(amt1_planck), + hex::encode(&assignment.exit_account_1[..4]), + assignment.output_amount_2, + format_balance(amt2_planck), + hex::encode(&assignment.exit_account_2[..4]) + ); + } else { + log_print!( + " Proof {}: {} ({}) -> 0x{}...", + i + 1, + assignment.output_amount_1, + format_balance(amt1_planck), + hex::encode(&assignment.exit_account_1[..4]) + ); + } + } + let pb = ProgressBar::new(num_proofs as u64); pb.set_style( ProgressStyle::default_bar() @@ -1483,18 +1658,15 @@ async fn run_multiround( pb.set_message(format!("Proof {}/{}", i + 1, num_proofs)); let proof_file = format!("{}/proof_{}.hex", round_dir, i + 1); - let exit_account_hex = format!("0x{}", hex::encode(exit_accounts[i].0)); // Use the funding account from the transfer info let funding_account_hex = format!("0x{}", hex::encode(transfer.funding_account.0)); - // Generate proof using internal function - // Use the actual transfer amount (not calculated round_amount) for storage key lookup - // All proofs use the same block hash for aggregation compatibility - generate_proof_internal( + // Generate proof with dual output assignment + generate_proof_with_dual_output( &hex::encode(secret.secret), transfer.amount, // Use actual transfer amount for storage key - &exit_account_hex, + &output_assignments[i], &format!("0x{}", hex::encode(proof_block_hash.0)), transfer.transfer_count, &funding_account_hex, @@ -1668,12 +1840,11 @@ async fn run_multiround( Ok(()) } -/// Internal proof generation that uses already-connected client -#[allow(clippy::too_many_arguments)] -async fn generate_proof_internal( +/// Generate a wormhole proof with dual outputs (used for random partitioning in multiround) +async fn generate_proof_with_dual_output( secret_hex: &str, funding_amount: u128, - exit_account_str: &str, + output_assignment: &ProofOutputAssignment, block_hash_str: &str, transfer_count: u64, funding_account_str: &str, @@ -1686,11 +1857,6 @@ async fn generate_proof_internal( crate::error::QuantusError::Generic(format!("Failed to convert secret: {:?}", e)) })?; - // Parse exit account - let exit_account_bytes = - parse_exit_account(exit_account_str).map_err(crate::error::QuantusError::Generic)?; - let exit_account_id = SubxtAccountId(exit_account_bytes); - // Parse funding account let funding_account_bytes = parse_exit_account(funding_account_str).map_err(crate::error::QuantusError::Generic)?; @@ -1794,11 +1960,11 @@ async fn generate_proof_internal( ) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - // Quantize amounts + // Quantize input amount let input_amount_quantized: u32 = quantize_funding_amount(funding_amount).map_err(crate::error::QuantusError::Generic)?; - let output_amount_quantized = compute_output_amount(input_amount_quantized, VOLUME_FEE_BPS); + // Use the output assignment directly (already quantized) let inputs = CircuitInputs { private: PrivateCircuitInputs { secret, @@ -1813,14 +1979,14 @@ async fn generate_proof_internal( input_amount: input_amount_quantized, }, public: PublicCircuitInputs { - output_amount_1: output_amount_quantized, - output_amount_2: 0, // No change output for single-output spend + output_amount_1: output_assignment.output_amount_1, + output_amount_2: output_assignment.output_amount_2, volume_fee_bps: VOLUME_FEE_BPS, nullifier: Nullifier::from_preimage(secret, transfer_count).hash.into(), - exit_account_1: BytesDigest::try_from(exit_account_id.as_ref() as &[u8]) + exit_account_1: BytesDigest::try_from(output_assignment.exit_account_1.as_ref()) + .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, + exit_account_2: BytesDigest::try_from(output_assignment.exit_account_2.as_ref()) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, - exit_account_2: BytesDigest::try_from([0u8; 32].as_ref()) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, // Unused block_hash: BytesDigest::try_from(block_hash.as_ref()) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, parent_hash, @@ -2223,8 +2389,8 @@ mod tests { let output_medium = compute_output_amount(input_medium, VOLUME_FEE_BPS); assert_eq!(output_medium, 9990); assert!( - (output_medium as u64) * 10000 <= - (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) + (output_medium as u64) * 10000 + <= (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) ); // Large amounts near u32::MAX @@ -2309,8 +2475,8 @@ mod tests { let input_amount = inputs.private.input_amount; let output_amount = inputs.public.output_amount_1 + inputs.public.output_amount_2; assert!( - (output_amount as u64) * 10000 <= - (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), + (output_amount as u64) * 10000 + <= (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), "Test inputs violate fee constraint" ); From 3f7171483b82455ce36f5a9c95e8b9989c58f495 Mon Sep 17 00:00:00 2001 From: illuzen Date: Thu, 12 Feb 2026 17:34:20 +0800 Subject: [PATCH 07/26] fix tests, cleanup unused function --- Cargo.lock | 93 ++------ Cargo.toml | 1 + src/cli/wormhole.rs | 418 ++++++++++------------------------ src/wallet/keystore.rs | 18 +- src/wallet/mod.rs | 26 ++- tests/wormhole_integration.rs | 46 ++-- 6 files changed, 192 insertions(+), 410 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00adf6c..ad34b2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3569,10 +3569,6 @@ dependencies = [ "rayon", ] -[[package]] -name = "plonky2_util" -version = "1.0.0" - [[package]] name = "plonky2_util" version = "1.0.0" @@ -3841,10 +3837,10 @@ dependencies = [ "p3-poseidon2", "p3-symmetric", "plonky2_maybe_rayon", - "plonky2_util 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "qp-plonky2-core 1.1.5", - "qp-plonky2-field 1.1.5", - "qp-plonky2-verifier 1.1.5", + "plonky2_util", + "qp-plonky2-core", + "qp-plonky2-field", + "qp-plonky2-verifier", "qp-poseidon-constants", "rand 0.8.5", "rand_chacha 0.3.1", @@ -3854,29 +3850,6 @@ dependencies = [ "web-time", ] -[[package]] -name = "qp-plonky2-core" -version = "1.0.0" -dependencies = [ - "ahash", - "anyhow", - "hashbrown 0.14.5", - "itertools 0.11.0", - "keccak-hash 0.8.0", - "log", - "num", - "p3-field", - "p3-goldilocks", - "p3-poseidon2", - "p3-symmetric", - "plonky2_util 1.0.0", - "qp-plonky2-field 1.1.3", - "qp-poseidon-constants", - "serde", - "static_assertions", - "unroll", -] - [[package]] name = "qp-plonky2-core" version = "1.1.5" @@ -3894,8 +3867,8 @@ dependencies = [ "p3-goldilocks", "p3-poseidon2", "p3-symmetric", - "plonky2_util 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "qp-plonky2-field 1.1.5", + "plonky2_util", + "qp-plonky2-field", "qp-poseidon-constants", "rand 0.8.5", "serde", @@ -3903,20 +3876,6 @@ dependencies = [ "unroll", ] -[[package]] -name = "qp-plonky2-field" -version = "1.1.3" -dependencies = [ - "anyhow", - "itertools 0.11.0", - "num", - "plonky2_util 1.0.0", - "rustc_version", - "serde", - "static_assertions", - "unroll", -] - [[package]] name = "qp-plonky2-field" version = "1.1.5" @@ -3926,7 +3885,7 @@ dependencies = [ "anyhow", "itertools 0.11.0", "num", - "plonky2_util 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "plonky2_util", "rand 0.8.5", "rustc_version", "serde", @@ -3951,33 +3910,9 @@ dependencies = [ "p3-goldilocks", "p3-poseidon2", "p3-symmetric", - "plonky2_util 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "qp-plonky2-core 1.1.5", - "qp-plonky2-field 1.1.5", - "qp-poseidon-constants", - "serde", - "static_assertions", - "unroll", -] - -[[package]] -name = "qp-plonky2-verifier" -version = "2.0.0" -dependencies = [ - "ahash", - "anyhow", - "hashbrown 0.14.5", - "itertools 0.11.0", - "keccak-hash 0.8.0", - "log", - "num", - "p3-field", - "p3-goldilocks", - "p3-poseidon2", - "p3-symmetric", - "plonky2_util 1.0.0", - "qp-plonky2-core 1.0.0", - "qp-plonky2-field 1.1.3", + "plonky2_util", + "qp-plonky2-core", + "qp-plonky2-field", "qp-poseidon-constants", "serde", "static_assertions", @@ -4070,6 +4005,7 @@ dependencies = [ "hex", "qp-plonky2", "qp-wormhole-circuit", + "qp-wormhole-inputs", "qp-wormhole-prover", "qp-zk-circuits-common", "rand 0.8.5", @@ -4083,6 +4019,7 @@ dependencies = [ "anyhow", "hex", "qp-plonky2", + "qp-wormhole-inputs", "qp-zk-circuits-common", ] @@ -4100,6 +4037,7 @@ dependencies = [ "anyhow", "qp-plonky2", "qp-wormhole-circuit", + "qp-wormhole-inputs", "qp-zk-circuits-common", ] @@ -4108,7 +4046,7 @@ name = "qp-wormhole-verifier" version = "1.0.1" dependencies = [ "anyhow", - "qp-plonky2-verifier 2.0.0", + "qp-plonky2-verifier", "qp-wormhole-inputs", ] @@ -4120,6 +4058,7 @@ dependencies = [ "hex", "qp-plonky2", "qp-poseidon-core", + "qp-wormhole-inputs", "serde", ] @@ -4148,6 +4087,7 @@ dependencies = [ "qp-rusty-crystals-hdwallet", "qp-wormhole-aggregator", "qp-wormhole-circuit", + "qp-wormhole-inputs", "qp-wormhole-prover", "qp-wormhole-verifier", "qp-zk-circuits-common", @@ -6043,6 +5983,7 @@ dependencies = [ "hex", "qp-plonky2", "qp-wormhole-circuit", + "qp-wormhole-inputs", "qp-zk-circuits-common", ] diff --git a/Cargo.toml b/Cargo.toml index da8491f..2f11112 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,6 +80,7 @@ qp-wormhole-circuit = { git = "https://github.com/Quantus-Network/qp-zk-circuits qp-wormhole-prover = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-prover", default-features = false, features = ["std"] } qp-wormhole-verifier = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-verifier", default-features = false, features = ["std"] } qp-wormhole-aggregator = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-aggregator", default-features = false, features = ["rayon", "std"] } +qp-wormhole-inputs = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-inputs", default-features = false, features = ["std"] } qp-zk-circuits-common = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-zk-circuits-common", default-features = false, features = ["std"] } qp-plonky2 = { version = "1.1.3", default-features = false, features = ["std", "rand"] } diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 7e40c0b..95a64b8 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -19,16 +19,15 @@ use qp_rusty_crystals_hdwallet::{ QUANTUS_WORMHOLE_CHAIN_ID, }; use qp_wormhole_circuit::{ - inputs::{ - AggregatedPublicCircuitInputs, CircuitInputs, PrivateCircuitInputs, PublicCircuitInputs, - }, + inputs::{CircuitInputs, ParseAggregatedPublicInputs, PrivateCircuitInputs}, nullifier::Nullifier, }; +use qp_wormhole_inputs::{AggregatedPublicCircuitInputs, PublicCircuitInputs}; use qp_wormhole_prover::WormholeProver; use qp_zk_circuits_common::{ circuit::{C, D, F}, storage_proof::prepare_proof_for_circuit, - utils::{BytesDigest, Digest}, + utils::{digest_felts_to_bytes, BytesDigest}, }; use rand::RngCore; use sp_core::{ @@ -578,7 +577,7 @@ pub enum WormholeCommands { #[arg(short, long, default_value = "2")] rounds: usize, - /// Amount per transfer in planck (default: 10 DEV) + /// Total amount in planck to partition across all proofs (default: 10 DEV) #[arg(short, long, default_value = "10000000000000")] amount: u128, @@ -613,9 +612,8 @@ pub async fn handle_wormhole_command( node_url: &str, ) -> crate::error::Result<()> { match command { - WormholeCommands::Transfer { secret, amount, from, password, password_file } => { - submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await - }, + WormholeCommands::Transfer { secret, amount, from, password, password_file } => + submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await, WormholeCommands::Generate { secret, amount, @@ -625,27 +623,47 @@ pub async fn handle_wormhole_command( funding_account, output, } => { + log_print!("Generating proof from existing transfer..."); + + // Connect to node + let quantus_client = QuantusClient::new(node_url).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to connect: {}", e)) + })?; + + // Parse exit account + let exit_account_bytes = + parse_exit_account(&exit_account).map_err(crate::error::QuantusError::Generic)?; + + // Quantize amount and compute output (single output, no change) + let input_amount_quantized = + quantize_funding_amount(amount).map_err(crate::error::QuantusError::Generic)?; + let output_amount = compute_output_amount(input_amount_quantized, VOLUME_FEE_BPS); + + let output_assignment = ProofOutputAssignment { + output_amount_1: output_amount, + exit_account_1: exit_account_bytes, + output_amount_2: 0, + exit_account_2: [0u8; 32], + }; + generate_proof( - secret, + &secret, amount, - exit_account, - block, + &output_assignment, + &block, transfer_count, - funding_account, - output, - node_url, + &funding_account, + &output, + &quantus_client, ) .await }, - WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => { - aggregate_proofs(proofs, output, depth, branching_factor).await - }, - WormholeCommands::VerifyAggregated { proof } => { - verify_aggregated_proof(proof, node_url).await - }, - WormholeCommands::ParseProof { proof, aggregated, verify } => { - parse_proof_file(proof, aggregated, verify).await - }, + WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => + aggregate_proofs(proofs, output, depth, branching_factor).await, + WormholeCommands::VerifyAggregated { proof } => + verify_aggregated_proof(proof, node_url).await, + WormholeCommands::ParseProof { proof, aggregated, verify } => + parse_proof_file(proof, aggregated, verify).await, WormholeCommands::Multiround { num_proofs, rounds, @@ -656,7 +674,7 @@ pub async fn handle_wormhole_command( keep_files, output_dir, dry_run, - } => { + } => run_multiround( num_proofs, rounds, @@ -669,8 +687,7 @@ pub async fn handle_wormhole_command( dry_run, node_url, ) - .await - }, + .await, } } @@ -778,206 +795,6 @@ async fn submit_wormhole_transfer( Ok(()) } -/// Generate a wormhole proof from an existing transfer -async fn generate_proof( - secret_hex: String, - funding_amount: u128, - exit_account_str: String, - block_hash_str: String, - transfer_count: u64, - funding_account_str: String, - output_file: String, - node_url: &str, -) -> crate::error::Result<()> { - log_print!("Generating proof from existing transfer..."); - - // Parse secret - let secret_array = - parse_secret_hex(&secret_hex).map_err(crate::error::QuantusError::Generic)?; - let secret: BytesDigest = secret_array.try_into().map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to convert secret: {:?}", e)) - })?; - - // Parse exit account - let exit_account_bytes = - parse_exit_account(&exit_account_str).map_err(crate::error::QuantusError::Generic)?; - let exit_account_id = SubxtAccountId(exit_account_bytes); - - // Parse funding account - let funding_account_bytes = - parse_exit_account(&funding_account_str).map_err(crate::error::QuantusError::Generic)?; - let funding_account = AccountId32::new(funding_account_bytes); - - // Parse block hash - let hash_bytes = hex::decode(block_hash_str.trim_start_matches("0x")) - .map_err(|e| crate::error::QuantusError::Generic(format!("Invalid block hash: {}", e)))?; - if hash_bytes.len() != 32 { - return Err(crate::error::QuantusError::Generic(format!( - "Block hash must be 32 bytes, got {}", - hash_bytes.len() - ))); - } - let hash: [u8; 32] = hash_bytes.try_into().unwrap(); - let block_hash = subxt::utils::H256::from(hash); - - // Connect to node - let quantus_client = QuantusClient::new(node_url) - .await - .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to connect: {}", e)))?; - let client = quantus_client.client(); - - log_verbose!("Connected to node, using block: {:?}", block_hash); - - // Generate unspendable account from secret - let unspendable_account = - qp_wormhole_circuit::unspendable_account::UnspendableAccount::from_secret(secret) - .account_id; - let unspendable_account_bytes_digest = - qp_zk_circuits_common::utils::digest_felts_to_bytes(unspendable_account); - let unspendable_account_bytes: [u8; 32] = unspendable_account_bytes_digest - .as_ref() - .try_into() - .expect("BytesDigest is always 32 bytes"); - - let from_account = funding_account.clone(); - let to_account = AccountId32::new(unspendable_account_bytes); - - // Get block - let blocks = - client.blocks().at(block_hash).await.map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) - })?; - - // Build storage key - let leaf_hash = qp_poseidon::PoseidonHasher::hash_storage::( - &( - NATIVE_ASSET_ID, - transfer_count, - from_account.clone(), - to_account.clone(), - funding_amount, - ) - .encode(), - ); - - let proof_address = quantus_node::api::storage().wormhole().transfer_proof(( - NATIVE_ASSET_ID, - transfer_count, - SubxtAccountId(from_account.clone().into()), - SubxtAccountId(to_account.clone().into()), - funding_amount, - )); - - let mut final_key = proof_address.to_root_bytes(); - final_key.extend_from_slice(&leaf_hash); - - // Verify storage key exists - let storage_api = client.storage().at(block_hash); - let val = storage_api - .fetch_raw(final_key.clone()) - .await - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - if val.is_none() { - return Err(crate::error::QuantusError::Generic( - "Storage key not found - transfer may not exist in this block".to_string(), - )); - } - - // Get storage proof - let proof_params = rpc_params![vec![to_hex(&final_key)], block_hash]; - let read_proof: ReadProof = quantus_client - .rpc_client() - .request("state_getReadProof", proof_params) - .await - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - - let header = blocks.header(); - let state_root = BytesDigest::try_from(header.state_root.as_bytes()) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - let parent_hash = BytesDigest::try_from(header.parent_hash.as_bytes()) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - let extrinsics_root = BytesDigest::try_from(header.extrinsics_root.as_bytes()) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - let digest = - header.digest.encode().try_into().map_err(|_| { - crate::error::QuantusError::Generic("Failed to encode digest".to_string()) - })?; - let block_number = header.number; - - // Prepare storage proof - let processed_storage_proof = prepare_proof_for_circuit( - read_proof.proof.iter().map(|proof| proof.0.clone()).collect(), - hex::encode(header.state_root.0), - leaf_hash, - ) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - - // Quantize amounts - let input_amount_quantized: u32 = - quantize_funding_amount(funding_amount).map_err(crate::error::QuantusError::Generic)?; - let output_amount_quantized = compute_output_amount(input_amount_quantized, VOLUME_FEE_BPS); - - let inputs = CircuitInputs { - private: PrivateCircuitInputs { - secret, - transfer_count, - funding_account: BytesDigest::try_from(funding_account.as_ref() as &[u8]) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, - storage_proof: processed_storage_proof, - unspendable_account: Digest::from(unspendable_account).into(), - state_root, - extrinsics_root, - digest, - input_amount: input_amount_quantized, - }, - public: PublicCircuitInputs { - output_amount_1: output_amount_quantized, - output_amount_2: 0, // No change output for single-output spend - volume_fee_bps: VOLUME_FEE_BPS, - nullifier: Nullifier::from_preimage(secret, transfer_count).hash.into(), - exit_account_1: BytesDigest::try_from(exit_account_id.as_ref() as &[u8]) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, - exit_account_2: BytesDigest::try_from([0u8; 32].as_ref()) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, // Unused - block_hash: BytesDigest::try_from(block_hash.as_ref()) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, - parent_hash, - block_number, - asset_id: NATIVE_ASSET_ID, - }, - }; - - log_verbose!("Generating ZK proof..."); - // Load prover from pre-built bins to ensure circuit digest matches on-chain verifier - let bins_dir = std::path::Path::new("generated-bins"); - let prover = - WormholeProver::new_from_files(&bins_dir.join("prover.bin"), &bins_dir.join("common.bin")) - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load prover: {}", e)) - })?; - let prover_next = prover - .commit(&inputs) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - let proof: ProofWithPublicInputs<_, _, 2> = prover_next.prove().map_err(|e| { - crate::error::QuantusError::Generic(format!("Proof generation failed: {}", e)) - })?; - - let public_inputs = PublicCircuitInputs::try_from(&proof) - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - - let proof_hex = hex::encode(proof.to_bytes()); - std::fs::write(&output_file, proof_hex).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to write proof: {}", e)) - })?; - - log_success!("Proof generated successfully!"); - log_success!("Output: {}", output_file); - log_success!("Block: {:?}", block_hash); - log_verbose!("Public inputs: {:?}", public_inputs); - - Ok(()) -} - async fn at_best_block( quantus_client: &QuantusClient, ) -> anyhow::Result>> { @@ -1057,7 +874,7 @@ async fn aggregate_proofs( .map_err(|e| crate::error::QuantusError::Generic(format!("Aggregation failed: {}", e)))?; // Parse and display aggregated public inputs - let aggregated_public_inputs = AggregatedPublicCircuitInputs::try_from_slice( + let aggregated_public_inputs = AggregatedPublicCircuitInputs::try_from_felts( aggregated_proof.proof.public_inputs.as_slice(), ) .map_err(|e| { @@ -1343,7 +1160,7 @@ async fn run_multiround( log_print!(""); // Validate parameters - if num_proofs < 1 || num_proofs > MULTIROUND_MAX_PROOFS { + if !(1..=MULTIROUND_MAX_PROOFS).contains(&num_proofs) { return Err(crate::error::QuantusError::Generic(format!( "num_proofs must be between 1 and {} (got: {})", MULTIROUND_MAX_PROOFS, num_proofs @@ -1663,7 +1480,7 @@ async fn run_multiround( let funding_account_hex = format!("0x{}", hex::encode(transfer.funding_account.0)); // Generate proof with dual output assignment - generate_proof_with_dual_output( + generate_proof( &hex::encode(secret.secret), transfer.amount, // Use actual transfer amount for storage key &output_assignments[i], @@ -1766,12 +1583,11 @@ async fn run_multiround( let final_balance = get_balance(&quantus_client, &wallet_address).await?; // Calculate expected balance change - // Total sent in round 1: num_proofs * amount - let total_sent = (num_proofs as u128) * amount; + // Total sent in round 1: the `amount` parameter is the total that was partitioned + let total_sent = amount; - // Total received in final round: num_proofs * final_round_amount - let final_round_amount = calculate_round_amount(amount, rounds); - let total_received = (num_proofs as u128) * final_round_amount; + // Total received in final round: apply fee deduction for each round + let total_received = calculate_round_amount(amount, rounds); // Expected net change (may be negative due to fees) let expected_change = total_received as i128 - total_sent as i128; @@ -1809,7 +1625,7 @@ async fn run_multiround( // The actual change may differ slightly due to transaction fees for the initial transfers let tolerance = (total_sent / 100).max(1_000_000_000_000); // 1% or 1 QNT minimum - let diff = (actual_change - expected_change).abs() as u128; + let diff = (actual_change - expected_change).unsigned_abs(); if diff <= tolerance { log_success!( " {} Balance verification PASSED (within tolerance of {} planck)", @@ -1841,7 +1657,7 @@ async fn run_multiround( } /// Generate a wormhole proof with dual outputs (used for random partitioning in multiround) -async fn generate_proof_with_dual_output( +async fn generate_proof( secret_hex: &str, funding_amount: u128, output_assignment: &ProofOutputAssignment, @@ -1972,7 +1788,7 @@ async fn generate_proof_with_dual_output( funding_account: BytesDigest::try_from(funding_account.as_ref() as &[u8]) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, storage_proof: processed_storage_proof, - unspendable_account: Digest::from(unspendable_account).into(), + unspendable_account: unspendable_account_bytes_digest, state_root, extrinsics_root, digest, @@ -1982,7 +1798,7 @@ async fn generate_proof_with_dual_output( output_amount_1: output_assignment.output_amount_1, output_amount_2: output_assignment.output_amount_2, volume_fee_bps: VOLUME_FEE_BPS, - nullifier: Nullifier::from_preimage(secret, transfer_count).hash.into(), + nullifier: digest_felts_to_bytes(Nullifier::from_preimage(secret, transfer_count).hash), exit_account_1: BytesDigest::try_from(output_assignment.exit_account_1.as_ref()) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, exit_account_2: BytesDigest::try_from(output_assignment.exit_account_2.as_ref()) @@ -2036,16 +1852,14 @@ async fn verify_aggregated_and_get_events( // Verify locally before submitting on-chain log_verbose!("Verifying aggregated proof locally before on-chain submission..."); - let aggregated_verifier_bytes = include_bytes!("../../generated-bins/aggregated_verifier.bin"); - let aggregated_common_bytes = include_bytes!("../../generated-bins/aggregated_common.bin"); - let verifier = - WormholeVerifier::new_from_bytes(aggregated_verifier_bytes, aggregated_common_bytes) - .map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to load aggregated verifier: {}", - e - )) - })?; + let bins_dir = Path::new("generated-bins"); + let verifier = WormholeVerifier::new_from_files( + &bins_dir.join("aggregated_verifier.bin"), + &bins_dir.join("aggregated_common.bin"), + ) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load aggregated verifier: {}", e)) + })?; // Use the verifier crate's ProofWithPublicInputs type (different from plonky2's) let proof = qp_wormhole_verifier::ProofWithPublicInputs::< @@ -2252,9 +2066,8 @@ fn run_multiround_dry_run( mod tests { use super::*; use plonky2::plonk::circuit_data::CircuitConfig; - use qp_wormhole_circuit::inputs::{ - AggregatedPublicCircuitInputs, CircuitInputs, PublicCircuitInputs, - }; + use qp_wormhole_circuit::inputs::{CircuitInputs, ParsePublicInputs}; + use qp_wormhole_inputs::{AggregatedPublicCircuitInputs, PublicCircuitInputs}; use qp_wormhole_prover::WormholeProver; use qp_wormhole_test_helpers::TestInputs; @@ -2265,6 +2078,13 @@ mod tests { CircuitConfig::standard_recursion_zk_config() } + /// Helper to build a verifier from the circuit for testing. + /// In production, verifiers load pre-built circuit data from files. + fn build_test_verifier() -> plonky2::plonk::circuit_data::VerifierCircuitData { + use qp_wormhole_circuit::circuit::circuit_logic::WormholeCircuit; + WormholeCircuit::new(test_circuit_config()).build_verifier() + } + #[test] fn test_compute_output_amount() { // 0.1% fee (10 bps): output = input * 9990 / 10000 @@ -2389,8 +2209,8 @@ mod tests { let output_medium = compute_output_amount(input_medium, VOLUME_FEE_BPS); assert_eq!(output_medium, 9990); assert!( - (output_medium as u64) * 10000 - <= (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) + (output_medium as u64) * 10000 <= + (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) ); // Large amounts near u32::MAX @@ -2475,8 +2295,8 @@ mod tests { let input_amount = inputs.private.input_amount; let output_amount = inputs.public.output_amount_1 + inputs.public.output_amount_2; assert!( - (output_amount as u64) * 10000 - <= (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), + (output_amount as u64) * 10000 <= + (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), "Test inputs violate fee constraint" ); @@ -2488,7 +2308,7 @@ mod tests { // Parse and verify public inputs from proof let parsed_public_inputs = - PublicCircuitInputs::try_from(&proof).expect("Failed to parse public inputs"); + PublicCircuitInputs::try_from_proof(&proof).expect("Failed to parse public inputs"); assert_eq!(parsed_public_inputs.asset_id, inputs.public.asset_id); assert_eq!(parsed_public_inputs.output_amount_1, inputs.public.output_amount_1); @@ -2502,7 +2322,7 @@ mod tests { assert_eq!(parsed_public_inputs.block_number, inputs.public.block_number); // Create verifier and verify proof - let verifier = WormholeVerifier::new(config, None); + let verifier = build_test_verifier(); verifier.verify(proof).expect("Proof verification failed"); } @@ -2529,12 +2349,12 @@ mod tests { assert_eq!(proof_bytes, read_bytes, "Proof bytes should match after file roundtrip"); // Deserialize and verify - let verifier = WormholeVerifier::new(config, None); + let verifier = build_test_verifier(); let deserialized_proof = plonky2::plonk::proof::ProofWithPublicInputs::< qp_zk_circuits_common::circuit::F, qp_zk_circuits_common::circuit::C, { qp_zk_circuits_common::circuit::D }, - >::from_bytes(read_bytes, &verifier.circuit_data.common) + >::from_bytes(read_bytes, &verifier.common) .expect("Failed to deserialize proof"); verifier @@ -2559,13 +2379,13 @@ mod tests { let proof_1 = prover_1.commit(&inputs_1).unwrap().prove().unwrap(); // Verify both proofs - let verifier = WormholeVerifier::new(config, None); + let verifier = build_test_verifier(); verifier.verify(proof_0.clone()).expect("Proof 0 verification failed"); verifier.verify(proof_1.clone()).expect("Proof 1 verification failed"); // Verify public inputs are different (different nullifiers, etc.) - let public_0 = PublicCircuitInputs::try_from(&proof_0).unwrap(); - let public_1 = PublicCircuitInputs::try_from(&proof_1).unwrap(); + let public_0 = PublicCircuitInputs::try_from_proof(&proof_0).unwrap(); + let public_1 = PublicCircuitInputs::try_from_proof(&proof_1).unwrap(); assert_ne!(public_0.nullifier, public_1.nullifier, "Nullifiers should be different"); assert_ne!(public_0.block_hash, public_1.block_hash, "Block hashes should be different"); @@ -2585,8 +2405,7 @@ mod tests { let proof = prover.commit(&inputs).unwrap().prove().unwrap(); // Create aggregator with default config (branching_factor=2, depth=1) - let verifier = WormholeVerifier::new(config, None); - let mut aggregator = WormholeProofAggregator::new(verifier.circuit_data); + let mut aggregator = WormholeProofAggregator::from_circuit_config(config); // Add proof to aggregator aggregator.push_proof(proof.clone()).expect("Failed to push proof"); @@ -2595,7 +2414,7 @@ mod tests { let aggregated_result = aggregator.aggregate().expect("Aggregation failed"); // Parse aggregated public inputs - let aggregated_public_inputs = AggregatedPublicCircuitInputs::try_from_slice( + let aggregated_public_inputs = AggregatedPublicCircuitInputs::try_from_felts( aggregated_result.proof.public_inputs.as_slice(), ) .expect("Failed to parse aggregated public inputs"); @@ -2641,8 +2460,7 @@ mod tests { let proof_1 = prover_1.commit(&inputs_1).unwrap().prove().unwrap(); // Create aggregator - let verifier = WormholeVerifier::new(config, None); - let mut aggregator = WormholeProofAggregator::new(verifier.circuit_data); + let mut aggregator = WormholeProofAggregator::from_circuit_config(config); // Add both proofs aggregator.push_proof(proof_0).expect("Failed to push proof 0"); @@ -2652,7 +2470,7 @@ mod tests { let aggregated_result = aggregator.aggregate().expect("Aggregation failed"); // Parse aggregated public inputs - let aggregated_public_inputs = AggregatedPublicCircuitInputs::try_from_slice( + let aggregated_public_inputs = AggregatedPublicCircuitInputs::try_from_felts( aggregated_result.proof.public_inputs.as_slice(), ) .expect("Failed to parse aggregated public inputs"); @@ -2680,27 +2498,31 @@ mod tests { /// Test that public inputs parsing matches expected structure #[test] fn test_public_inputs_structure() { - use qp_wormhole_circuit::inputs::{ + use qp_wormhole_inputs::{ ASSET_ID_INDEX, BLOCK_HASH_END_INDEX, BLOCK_HASH_START_INDEX, BLOCK_NUMBER_INDEX, - EXIT_ACCOUNT_END_INDEX, EXIT_ACCOUNT_START_INDEX, NULLIFIER_END_INDEX, - NULLIFIER_START_INDEX, OUTPUT_AMOUNT_INDEX, PARENT_HASH_END_INDEX, + EXIT_ACCOUNT_1_END_INDEX, EXIT_ACCOUNT_1_START_INDEX, EXIT_ACCOUNT_2_END_INDEX, + EXIT_ACCOUNT_2_START_INDEX, NULLIFIER_END_INDEX, NULLIFIER_START_INDEX, + OUTPUT_AMOUNT_1_INDEX, OUTPUT_AMOUNT_2_INDEX, PARENT_HASH_END_INDEX, PARENT_HASH_START_INDEX, PUBLIC_INPUTS_FELTS_LEN, VOLUME_FEE_BPS_INDEX, }; - // Verify expected public inputs layout - assert_eq!(PUBLIC_INPUTS_FELTS_LEN, 20, "Public inputs should be 20 field elements"); + // Verify expected public inputs layout for dual-output circuit + assert_eq!(PUBLIC_INPUTS_FELTS_LEN, 25, "Public inputs should be 25 field elements"); assert_eq!(ASSET_ID_INDEX, 0, "Asset ID should be first"); - assert_eq!(OUTPUT_AMOUNT_INDEX, 1, "Output amount should be second"); - assert_eq!(VOLUME_FEE_BPS_INDEX, 2, "Volume fee BPS should be third"); - assert_eq!(NULLIFIER_START_INDEX, 3, "Nullifier should start at index 3"); - assert_eq!(NULLIFIER_END_INDEX, 7, "Nullifier should end at index 7"); - assert_eq!(EXIT_ACCOUNT_START_INDEX, 7, "Exit account should start at index 7"); - assert_eq!(EXIT_ACCOUNT_END_INDEX, 11, "Exit account should end at index 11"); - assert_eq!(BLOCK_HASH_START_INDEX, 11, "Block hash should start at index 11"); - assert_eq!(BLOCK_HASH_END_INDEX, 15, "Block hash should end at index 15"); - assert_eq!(PARENT_HASH_START_INDEX, 15, "Parent hash should start at index 15"); - assert_eq!(PARENT_HASH_END_INDEX, 19, "Parent hash should end at index 19"); - assert_eq!(BLOCK_NUMBER_INDEX, 19, "Block number should be at index 19"); + assert_eq!(OUTPUT_AMOUNT_1_INDEX, 1, "Output amount 1 should be at index 1"); + assert_eq!(OUTPUT_AMOUNT_2_INDEX, 2, "Output amount 2 should be at index 2"); + assert_eq!(VOLUME_FEE_BPS_INDEX, 3, "Volume fee BPS should be at index 3"); + assert_eq!(NULLIFIER_START_INDEX, 4, "Nullifier should start at index 4"); + assert_eq!(NULLIFIER_END_INDEX, 8, "Nullifier should end at index 8"); + assert_eq!(EXIT_ACCOUNT_1_START_INDEX, 8, "Exit account 1 should start at index 8"); + assert_eq!(EXIT_ACCOUNT_1_END_INDEX, 12, "Exit account 1 should end at index 12"); + assert_eq!(EXIT_ACCOUNT_2_START_INDEX, 12, "Exit account 2 should start at index 12"); + assert_eq!(EXIT_ACCOUNT_2_END_INDEX, 16, "Exit account 2 should end at index 16"); + assert_eq!(BLOCK_HASH_START_INDEX, 16, "Block hash should start at index 16"); + assert_eq!(BLOCK_HASH_END_INDEX, 20, "Block hash should end at index 20"); + assert_eq!(PARENT_HASH_START_INDEX, 20, "Parent hash should start at index 20"); + assert_eq!(PARENT_HASH_END_INDEX, 24, "Parent hash should end at index 24"); + assert_eq!(BLOCK_NUMBER_INDEX, 24, "Block number should be at index 24"); } /// Test that constants match expected on-chain configuration @@ -2745,14 +2567,17 @@ async fn parse_proof_file( log_print!("Proof size: {} bytes", proof_bytes.len()); + let bins_dir = Path::new("generated-bins"); + if aggregated { // Load aggregated verifier - let verifier_bytes = include_bytes!("../../generated-bins/aggregated_verifier.bin"); - let common_bytes = include_bytes!("../../generated-bins/aggregated_common.bin"); - let verifier = - WormholeVerifier::new_from_bytes(verifier_bytes, common_bytes).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) - })?; + let verifier = WormholeVerifier::new_from_files( + &bins_dir.join("aggregated_verifier.bin"), + &bins_dir.join("aggregated_common.bin"), + ) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) + })?; // Deserialize proof using verifier's types let proof = qp_wormhole_verifier::ProofWithPublicInputs::< @@ -2818,12 +2643,13 @@ async fn parse_proof_file( } } else { // Load leaf verifier - let verifier_bytes = include_bytes!("../../generated-bins/verifier.bin"); - let common_bytes = include_bytes!("../../generated-bins/common.bin"); - let verifier = - WormholeVerifier::new_from_bytes(verifier_bytes, common_bytes).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) - })?; + let verifier = WormholeVerifier::new_from_files( + &bins_dir.join("verifier.bin"), + &bins_dir.join("common.bin"), + ) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) + })?; // Deserialize proof using verifier's types let proof = qp_wormhole_verifier::ProofWithPublicInputs::< diff --git a/src/wallet/keystore.rs b/src/wallet/keystore.rs index a8a9b28..752a8f9 100644 --- a/src/wallet/keystore.rs +++ b/src/wallet/keystore.rs @@ -6,6 +6,8 @@ /// - Managing wallet files on disk with quantum-resistant security use crate::error::{Result, WalletError}; use qp_rusty_crystals_dilithium::ml_dsa_87::{Keypair, PublicKey, SecretKey}; +#[cfg(test)] +use qp_rusty_crystals_hdwallet::SensitiveBytes32; use serde::{Deserialize, Serialize}; #[cfg(test)] use sp_core::crypto::Ss58AddressFormat; @@ -281,8 +283,8 @@ mod tests { #[test] fn test_quantum_keypair_from_dilithium_keypair() { // Generate a test keypair - let entropy = [1u8; 32]; - let dilithium_keypair = Keypair::generate(&entropy); + let mut entropy = [1u8; 32]; + let dilithium_keypair = Keypair::generate(SensitiveBytes32::from(&mut entropy)); // Convert to QuantumKeyPair let quantum_keypair = QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); @@ -295,8 +297,8 @@ mod tests { #[test] fn test_quantum_keypair_to_dilithium_keypair_roundtrip() { // Generate a test keypair - let entropy = [2u8; 32]; - let original_keypair = Keypair::generate(&entropy); + let mut entropy = [2u8; 32]; + let original_keypair = Keypair::generate(SensitiveBytes32::from(&mut entropy)); // Convert to QuantumKeyPair and back let quantum_keypair = QuantumKeyPair::from_dilithium_keypair(&original_keypair); @@ -420,8 +422,8 @@ mod tests { // Start with a Dilithium keypair sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::custom(189)); - let entropy = [3u8; 32]; - let dilithium_keypair = Keypair::generate(&entropy); + let mut entropy = [3u8; 32]; + let dilithium_keypair = Keypair::generate(SensitiveBytes32::from(&mut entropy)); // Convert through different paths let quantum_from_dilithium = QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); @@ -664,8 +666,8 @@ mod tests { fn test_keypair_data_integrity() { // Generate multiple keypairs and verify they maintain data integrity for i in 0..5 { - let entropy = [i as u8; 32]; - let dilithium_keypair = Keypair::generate(&entropy); + let mut entropy = [i as u8; 32]; + let dilithium_keypair = Keypair::generate(SensitiveBytes32::from(&mut entropy)); let quantum_keypair = QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); // Print actual key sizes for debugging (first iteration only) diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 3daa1c0..0837d2d 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -15,8 +15,8 @@ use rand::{rng, RngCore}; use serde::{Deserialize, Serialize}; use sp_runtime::traits::IdentifyAccount; -/// Default derivation path for Quantus wallets: m/44'/189189'/0'/0/0 -pub const DEFAULT_DERIVATION_PATH: &str = "m/44'/189189'/0'/0/0"; +/// Default derivation path for Quantus wallets: m/44'/189189'/0'/0'/0' +pub const DEFAULT_DERIVATION_PATH: &str = "m/44'/189189'/0'/0'/0'"; /// Wallet information structure #[derive(Debug, Clone, Serialize, Deserialize)] @@ -599,8 +599,10 @@ mod tests { let keystore = keystore::Keystore::new(temp_dir.path()); // Create test wallet data - let entropy = [1u8; 32]; // Use fixed entropy for deterministic tests - let dilithium_keypair = qp_rusty_crystals_dilithium::ml_dsa_87::Keypair::generate(&entropy); + let mut entropy = [1u8; 32]; // Use fixed entropy for deterministic tests + let dilithium_keypair = qp_rusty_crystals_dilithium::ml_dsa_87::Keypair::generate( + SensitiveBytes32::from(&mut entropy), + ); let quantum_keypair = keystore::QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); let mut metadata = std::collections::HashMap::new(); @@ -649,8 +651,10 @@ mod tests { #[tokio::test] async fn test_quantum_keypair_address_generation() { // Generate keypair - let entropy = [2u8; 32]; // Use different entropy for variety - let dilithium_keypair = qp_rusty_crystals_dilithium::ml_dsa_87::Keypair::generate(&entropy); + let mut entropy = [2u8; 32]; // Use different entropy for variety + let dilithium_keypair = qp_rusty_crystals_dilithium::ml_dsa_87::Keypair::generate( + SensitiveBytes32::from(&mut entropy), + ); let quantum_keypair = keystore::QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); // Test address generation @@ -673,8 +677,10 @@ mod tests { let keystore = keystore::Keystore::new(temp_dir.path()); // Create and encrypt wallet data - let entropy = [3u8; 32]; // Use different entropy for each test - let dilithium_keypair = qp_rusty_crystals_dilithium::ml_dsa_87::Keypair::generate(&entropy); + let mut entropy = [3u8; 32]; // Use different entropy for each test + let dilithium_keypair = qp_rusty_crystals_dilithium::ml_dsa_87::Keypair::generate( + SensitiveBytes32::from(&mut entropy), + ); let quantum_keypair = keystore::QuantumKeyPair::from_dilithium_keypair(&dilithium_keypair); let wallet_data = keystore::WalletData { @@ -767,8 +773,8 @@ mod tests { let (wallet_manager, _temp_dir) = create_test_wallet_manager().await; let test_mnemonic = "orchard answer curve patient visual flower maze noise retreat penalty cage small earth domain scan pitch bottom crunch theme club client swap slice raven"; - let expected_address = "qznMJss7Ls1SWBhvvL2CSHVbgTxEfnL9GgpvMTq5CWMEwfCoe"; // default derivation path index 0 - let expected_address_no_derive = "qznBvupPsA9T8VJDuTDokKPiNUe88zMMUtHGA1AsGc8fXKSSA"; + let expected_address = "qzoog56PJKvDwqo9GwkzRN74kxEgDEspxu5zVA62y18ttt3tG"; // default derivation path index 0 + let expected_address_no_derive = "qzofkFbmnEYLX6iHwqJ9uKYXFi7ypQwcBBMxcYYLVD17vGpsm"; let imported_wallet = wallet_manager .import_wallet("imported-test-wallet", test_mnemonic, Some("import-password")) diff --git a/tests/wormhole_integration.rs b/tests/wormhole_integration.rs index c68acf5..f048184 100644 --- a/tests/wormhole_integration.rs +++ b/tests/wormhole_integration.rs @@ -16,17 +16,16 @@ use plonky2::plonk::{circuit_data::CircuitConfig, proof::ProofWithPublicInputs}; use qp_wormhole_circuit::{ - inputs::{ - AggregatedPublicCircuitInputs, CircuitInputs, PrivateCircuitInputs, PublicCircuitInputs, - }, + inputs::{CircuitInputs, PrivateCircuitInputs}, nullifier::Nullifier, }; +use qp_wormhole_inputs::{AggregatedPublicCircuitInputs, PublicCircuitInputs}; use qp_wormhole_prover::WormholeProver; use qp_zk_circuits_common::{ circuit::{C, D, F}, storage_proof::prepare_proof_for_circuit, - utils::{BytesDigest, Digest}, + utils::{digest_felts_to_bytes, BytesDigest}, }; use quantus_cli::{ chain::{ @@ -410,19 +409,22 @@ async fn generate_proof_from_transfer( funding_account: BytesDigest::try_from(transfer_data.funding_account.as_ref() as &[u8]) .map_err(|e| format!("Failed to convert funding account: {}", e))?, storage_proof: processed_storage_proof, - unspendable_account: Digest::from(transfer_data.unspendable_account).into(), + unspendable_account: digest_felts_to_bytes(transfer_data.unspendable_account), state_root, extrinsics_root, digest, input_amount: input_amount_quantized, }, public: PublicCircuitInputs { - output_amount: output_amount_quantized, + output_amount_1: output_amount_quantized, + output_amount_2: 0, // No change output for single-output spend volume_fee_bps: VOLUME_FEE_BPS, - nullifier: Nullifier::from_preimage(secret_digest, transfer_data.transfer_count) - .hash - .into(), - exit_account: exit_account_digest, + nullifier: digest_felts_to_bytes( + Nullifier::from_preimage(secret_digest, transfer_data.transfer_count).hash, + ), + exit_account_1: exit_account_digest, + exit_account_2: BytesDigest::try_from([0u8; 32].as_ref()) + .map_err(|e| format!("Failed to convert zero exit account: {}", e))?, block_hash: BytesDigest::try_from(block_hash.as_ref()) .map_err(|e| format!("Failed to convert block hash: {}", e))?, parent_hash, @@ -438,7 +440,8 @@ async fn generate_proof_from_transfer( let proof: ProofWithPublicInputs<_, _, 2> = prover_next.prove().map_err(|e| format!("Proof generation failed: {}", e))?; - let public_inputs = PublicCircuitInputs::try_from(&proof) + use qp_wormhole_circuit::inputs::ParsePublicInputs; + let public_inputs = PublicCircuitInputs::try_from_proof(&proof) .map_err(|e| format!("Failed to parse public inputs: {}", e))?; let proof_bytes = proof.to_bytes(); @@ -529,10 +532,12 @@ fn aggregate_proofs( println!(" Adding proof {} to aggregator...", idx + 1); println!(" Public inputs:"); println!(" asset_id: {}", ctx.public_inputs.asset_id); - println!(" output_amount: {}", ctx.public_inputs.output_amount); + println!(" output_amount_1: {}", ctx.public_inputs.output_amount_1); + println!(" output_amount_2: {}", ctx.public_inputs.output_amount_2); println!(" volume_fee_bps: {}", ctx.public_inputs.volume_fee_bps); println!(" nullifier: {:?}", ctx.public_inputs.nullifier); - println!(" exit_account: {:?}", ctx.public_inputs.exit_account); + println!(" exit_account_1: {:?}", ctx.public_inputs.exit_account_1); + println!(" exit_account_2: {:?}", ctx.public_inputs.exit_account_2); println!(" block_hash: {:?}", ctx.public_inputs.block_hash); println!(" parent_hash: {:?}", ctx.public_inputs.parent_hash); println!(" block_number: {}", ctx.public_inputs.block_number); @@ -545,7 +550,8 @@ fn aggregate_proofs( let aggregated_result = aggregator.aggregate().map_err(|e| format!("Aggregation failed: {}", e))?; - let public_inputs = AggregatedPublicCircuitInputs::try_from_slice( + use qp_wormhole_circuit::inputs::ParseAggregatedPublicInputs; + let public_inputs = AggregatedPublicCircuitInputs::try_from_felts( aggregated_result.proof.public_inputs.as_slice(), ) .map_err(|e| format!("Failed to parse aggregated public inputs: {}", e))?; @@ -694,8 +700,8 @@ async fn test_single_proof_on_chain_verification() { .expect("Failed to generate proof"); println!( - " Public inputs - output_amount: {}, nullifier: {:?}", - proof_context.public_inputs.output_amount, proof_context.public_inputs.nullifier + " Public inputs - output_amount_1: {}, nullifier: {:?}", + proof_context.public_inputs.output_amount_1, proof_context.public_inputs.nullifier ); // Submit for on-chain verification @@ -721,7 +727,7 @@ async fn test_single_proof_on_chain_verification() { // Compute expected miner fee from public inputs (single proof) let fee_bps = proof_context.public_inputs.volume_fee_bps; - let exit_u128 = (proof_context.public_inputs.output_amount as u128) * SCALE_DOWN_FACTOR; + let exit_u128 = (proof_context.public_inputs.output_amount_1 as u128) * SCALE_DOWN_FACTOR; let expected_miner_fee = expected_miner_fee_u128(exit_u128, fee_bps); assert!(expected_miner_fee > 0, "expected miner fee should be > 0"); @@ -826,8 +832,8 @@ async fn test_aggregated_proof_on_chain_verification() { .expect("Failed to generate proof"); println!( - " Public inputs - output_amount: {}, nullifier: {:?}", - proof_context.public_inputs.output_amount, proof_context.public_inputs.nullifier + " Public inputs - output_amount_1: {}, nullifier: {:?}", + proof_context.public_inputs.output_amount_1, proof_context.public_inputs.nullifier ); proof_contexts.push(proof_context); @@ -954,7 +960,7 @@ async fn test_single_proof_exit_account_verification() { // Verify the exit account in public inputs matches what we specified let exit_account_from_proof: [u8; 32] = proof_context .public_inputs - .exit_account + .exit_account_1 .as_ref() .try_into() .expect("Exit account should be 32 bytes"); From 75c0b989e6ec07796721eda64c70f8f99a10a48e Mon Sep 17 00:00:00 2001 From: illuzen Date: Thu, 12 Feb 2026 17:42:59 +0800 Subject: [PATCH 08/26] taplo + breakup multiround --- Cargo.toml | 2 +- src/cli/wormhole.rs | 728 +++++++++++++++++++++++++------------------- 2 files changed, 424 insertions(+), 306 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2f11112..cd6b34a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,7 +82,7 @@ qp-wormhole-verifier = { git = "https://github.com/Quantus-Network/qp-zk-circuit qp-wormhole-aggregator = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-aggregator", default-features = false, features = ["rayon", "std"] } qp-wormhole-inputs = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-inputs", default-features = false, features = ["std"] } qp-zk-circuits-common = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-zk-circuits-common", default-features = false, features = ["std"] } -qp-plonky2 = { version = "1.1.3", default-features = false, features = ["std", "rand"] } +qp-plonky2 = { version = "1.1.3", default-features = false, features = ["rand", "std"] } [dev-dependencies] tempfile = "3.8" diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 95a64b8..75feb4c 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -612,8 +612,9 @@ pub async fn handle_wormhole_command( node_url: &str, ) -> crate::error::Result<()> { match command { - WormholeCommands::Transfer { secret, amount, from, password, password_file } => - submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await, + WormholeCommands::Transfer { secret, amount, from, password, password_file } => { + submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await + }, WormholeCommands::Generate { secret, amount, @@ -658,12 +659,15 @@ pub async fn handle_wormhole_command( ) .await }, - WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => - aggregate_proofs(proofs, output, depth, branching_factor).await, - WormholeCommands::VerifyAggregated { proof } => - verify_aggregated_proof(proof, node_url).await, - WormholeCommands::ParseProof { proof, aggregated, verify } => - parse_proof_file(proof, aggregated, verify).await, + WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => { + aggregate_proofs(proofs, output, depth, branching_factor).await + }, + WormholeCommands::VerifyAggregated { proof } => { + verify_aggregated_proof(proof, node_url).await + }, + WormholeCommands::ParseProof { proof, aggregated, verify } => { + parse_proof_file(proof, aggregated, verify).await + }, WormholeCommands::Multiround { num_proofs, rounds, @@ -674,7 +678,7 @@ pub async fn handle_wormhole_command( keep_files, output_dir, dry_run, - } => + } => { run_multiround( num_proofs, rounds, @@ -687,7 +691,8 @@ pub async fn handle_wormhole_command( dry_run, node_url, ) - .await, + .await + }, } } @@ -1137,29 +1142,26 @@ fn parse_transfer_events( Ok(transfer_infos) } -/// Run the multi-round wormhole flow -#[allow(clippy::too_many_arguments)] -async fn run_multiround( +/// Configuration for multiround execution +struct MultiroundConfig { num_proofs: usize, rounds: usize, amount: u128, - wallet_name: String, - password: Option, - password_file: Option, - keep_files: bool, output_dir: String, - dry_run: bool, - node_url: &str, -) -> crate::error::Result<()> { - use colored::Colorize; + keep_files: bool, +} - log_print!(""); - log_print!("=================================================="); - log_print!(" Wormhole Multi-Round Flow Test"); - log_print!("=================================================="); - log_print!(""); +/// Wallet context for multiround execution +struct MultiroundWalletContext { + wallet_name: String, + wallet_address: String, + wallet_account_id: SubxtAccountId, + keypair: QuantumKeyPair, + mnemonic: String, +} - // Validate parameters +/// Validate multiround parameters +fn validate_multiround_params(num_proofs: usize, rounds: usize) -> crate::error::Result<()> { if !(1..=MULTIROUND_MAX_PROOFS).contains(&num_proofs) { return Err(crate::error::QuantusError::Generic(format!( "num_proofs must be between 1 and {} (got: {})", @@ -1172,11 +1174,18 @@ async fn run_multiround( rounds ))); } + Ok(()) +} - // Load wallet +/// Load wallet and prepare context for multiround execution +fn load_multiround_wallet( + wallet_name: &str, + password: Option, + password_file: Option, +) -> crate::error::Result { let wallet_manager = WalletManager::new()?; - let wallet_password = password::get_wallet_password(&wallet_name, password, password_file)?; - let wallet_data = wallet_manager.load_wallet(&wallet_name, &wallet_password)?; + let wallet_password = password::get_wallet_password(wallet_name, password, password_file)?; + let wallet_data = wallet_manager.load_wallet(wallet_name, &wallet_password)?; let wallet_address = wallet_data.keypair.to_account_id_ss58check(); let wallet_account_id = SubxtAccountId(wallet_data.keypair.to_account_id_32().into()); @@ -1199,34 +1208,370 @@ async fn run_multiround( }, }; + Ok(MultiroundWalletContext { + wallet_name: wallet_name.to_string(), + wallet_address, + wallet_account_id, + keypair: wallet_data.keypair, + mnemonic, + }) +} + +/// Print multiround configuration summary +fn print_multiround_config(config: &MultiroundConfig, wallet: &MultiroundWalletContext) { + use colored::Colorize; + log_print!("{}", "Configuration:".bright_cyan()); - log_print!(" Wallet: {}", wallet_name); - log_print!(" Wallet address: {}", wallet_address); + log_print!(" Wallet: {}", wallet.wallet_name); + log_print!(" Wallet address: {}", wallet.wallet_address); log_print!( " Total amount: {} ({}) - randomly partitioned across {} proofs", - amount, - format_balance(amount), - num_proofs + config.amount, + format_balance(config.amount), + config.num_proofs ); - log_print!(" Proofs per round: {}", num_proofs); - log_print!(" Rounds: {}", rounds); + log_print!(" Proofs per round: {}", config.num_proofs); + log_print!(" Rounds: {}", config.rounds); log_print!( " Aggregation: branching_factor={}, depth={}", MULTIROUND_BRANCHING_FACTOR, MULTIROUND_DEPTH ); - log_print!(" Output directory: {}", output_dir); - log_print!(" Keep files: {}", keep_files); - log_print!(" Dry run: {}", dry_run); + log_print!(" Output directory: {}", config.output_dir); + log_print!(" Keep files: {}", config.keep_files); log_print!(""); // Show expected amounts per round log_print!("{}", "Expected amounts per round:".bright_cyan()); - for r in 1..=rounds { - let round_amount = calculate_round_amount(amount, r); + for r in 1..=config.rounds { + let round_amount = calculate_round_amount(config.amount, r); log_print!(" Round {}: {} ({})", r, round_amount, format_balance(round_amount)); } log_print!(""); +} + +/// Execute initial transfers from wallet to wormhole addresses (round 1 only) +async fn execute_initial_transfers( + quantus_client: &QuantusClient, + wallet: &MultiroundWalletContext, + secrets: &[WormholePair], + amount: u128, + num_proofs: usize, +) -> crate::error::Result> { + use colored::Colorize; + + log_print!("{}", "Step 1: Sending wormhole transfers from wallet...".bright_yellow()); + + // Randomly partition the total amount among proofs + let min_per_proof = SCALE_DOWN_FACTOR; // 0.01 DEV (minimum quantizable amount) + let partition_amounts = random_partition(amount, num_proofs, min_per_proof); + log_print!(" Random partition of {} ({}):", amount, format_balance(amount)); + for (i, &amt) in partition_amounts.iter().enumerate() { + log_print!(" Proof {}: {} ({})", i + 1, amt, format_balance(amt)); + } + + let pb = ProgressBar::new(num_proofs as u64); + pb.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") + .unwrap() + .progress_chars("#>-"), + ); + + let client = quantus_client.client(); + let mut transfers = Vec::new(); + + for (i, secret) in secrets.iter().enumerate() { + pb.set_message(format!("Transfer {}/{}", i + 1, num_proofs)); + + let wormhole_address = SubxtAccountId(secret.address); + let transfer_amount = partition_amounts[i]; + + // Submit transfer + let transfer_tx = quantus_node::api::tx().wormhole().transfer_native( + subxt::ext::subxt_core::utils::MultiAddress::Id(wormhole_address.clone()), + transfer_amount, + ); + + let quantum_keypair = QuantumKeyPair { + public_key: wallet.keypair.public_key.clone(), + private_key: wallet.keypair.private_key.clone(), + }; + + submit_transaction( + quantus_client, + &quantum_keypair, + transfer_tx, + None, + ExecutionMode { finalized: false, wait_for_transaction: true }, + ) + .await + .map_err(|e| crate::error::QuantusError::Generic(format!("Transfer failed: {}", e)))?; + + // Get the block and find our event + let block = at_best_block(quantus_client).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) + })?; + let block_hash = block.hash(); + + let events_api = client.events().at(block_hash).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get events: {}", e)) + })?; + + // Find our transfer event + let event = events_api + .find::() + .find(|e| if let Ok(evt) = e { evt.to.0 == secret.address } else { false }) + .ok_or_else(|| { + crate::error::QuantusError::Generic("No matching transfer event found".to_string()) + })? + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Event decode error: {}", e)) + })?; + + let funding_account_bytes = wallet.keypair.to_account_id_32(); + transfers.push(TransferInfo { + block_hash, + transfer_count: event.transfer_count, + amount: transfer_amount, + wormhole_address, + funding_account: SubxtAccountId(funding_account_bytes.into()), + }); + + pb.inc(1); + } + pb.finish_with_message("Transfers complete"); + + Ok(transfers) +} + +/// Generate proofs for a round with random output partitioning +async fn generate_round_proofs( + quantus_client: &QuantusClient, + secrets: &[WormholePair], + transfers: &[TransferInfo], + exit_accounts: &[SubxtAccountId], + round_dir: &str, + num_proofs: usize, +) -> crate::error::Result> { + use colored::Colorize; + + log_print!("{}", "Step 2: Generating proofs...".bright_yellow()); + + // All proofs in an aggregation batch must use the same block for storage proofs. + let proof_block = at_best_block(quantus_client) + .await + .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)))?; + let proof_block_hash = proof_block.hash(); + log_print!(" Using block {} for all proofs", hex::encode(proof_block_hash.0)); + + // Collect input amounts and exit accounts for random assignment + let input_amounts: Vec = transfers.iter().map(|t| t.amount).collect(); + let exit_account_bytes: Vec<[u8; 32]> = exit_accounts.iter().map(|a| a.0).collect(); + + // Compute random output assignments (each proof can have 2 outputs) + let output_assignments = + compute_random_output_assignments(&input_amounts, &exit_account_bytes, VOLUME_FEE_BPS); + + // Log the random partition + log_print!(" Random output partition:"); + for (i, assignment) in output_assignments.iter().enumerate() { + let amt1_planck = (assignment.output_amount_1 as u128) * SCALE_DOWN_FACTOR; + if assignment.output_amount_2 > 0 { + let amt2_planck = (assignment.output_amount_2 as u128) * SCALE_DOWN_FACTOR; + log_print!( + " Proof {}: {} ({}) -> 0x{}..., {} ({}) -> 0x{}...", + i + 1, + assignment.output_amount_1, + format_balance(amt1_planck), + hex::encode(&assignment.exit_account_1[..4]), + assignment.output_amount_2, + format_balance(amt2_planck), + hex::encode(&assignment.exit_account_2[..4]) + ); + } else { + log_print!( + " Proof {}: {} ({}) -> 0x{}...", + i + 1, + assignment.output_amount_1, + format_balance(amt1_planck), + hex::encode(&assignment.exit_account_1[..4]) + ); + } + } + + let pb = ProgressBar::new(num_proofs as u64); + pb.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") + .unwrap() + .progress_chars("#>-"), + ); + + let mut proof_files = Vec::new(); + for (i, (secret, transfer)) in secrets.iter().zip(transfers.iter()).enumerate() { + pb.set_message(format!("Proof {}/{}", i + 1, num_proofs)); + + let proof_file = format!("{}/proof_{}.hex", round_dir, i + 1); + + // Use the funding account from the transfer info + let funding_account_hex = format!("0x{}", hex::encode(transfer.funding_account.0)); + + // Generate proof with dual output assignment + generate_proof( + &hex::encode(secret.secret), + transfer.amount, // Use actual transfer amount for storage key + &output_assignments[i], + &format!("0x{}", hex::encode(proof_block_hash.0)), + transfer.transfer_count, + &funding_account_hex, + &proof_file, + quantus_client, + ) + .await?; + + proof_files.push(proof_file); + pb.inc(1); + } + pb.finish_with_message("Proofs generated"); + + Ok(proof_files) +} + +/// Derive wormhole secrets for a round +fn derive_round_secrets( + mnemonic: &str, + round: usize, + num_proofs: usize, +) -> crate::error::Result> { + let pb = ProgressBar::new(num_proofs as u64); + pb.set_style( + ProgressStyle::default_bar() + .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") + .unwrap() + .progress_chars("#>-"), + ); + pb.set_message("Deriving secrets..."); + + let mut secrets = Vec::new(); + for i in 1..=num_proofs { + let secret = derive_wormhole_secret(mnemonic, round, i)?; + secrets.push(secret); + pb.inc(1); + } + pb.finish_with_message("Secrets derived"); + + Ok(secrets) +} + +/// Verify final balance and print summary +fn verify_final_balance( + initial_balance: u128, + final_balance: u128, + total_sent: u128, + rounds: usize, + num_proofs: usize, +) { + use colored::Colorize; + + log_print!("{}", "Balance Verification:".bright_cyan()); + + // Total received in final round: apply fee deduction for each round + let total_received = calculate_round_amount(total_sent, rounds); + + // Expected net change (may be negative due to fees) + let expected_change = total_received as i128 - total_sent as i128; + let actual_change = final_balance as i128 - initial_balance as i128; + + log_print!(" Initial balance: {} ({})", initial_balance, format_balance(initial_balance)); + log_print!(" Final balance: {} ({})", final_balance, format_balance(final_balance)); + log_print!(""); + log_print!(" Total sent (round 1): {} ({})", total_sent, format_balance(total_sent)); + log_print!( + " Total received (round {}): {} ({})", + rounds, + total_received, + format_balance(total_received) + ); + log_print!(""); + + // Format signed amounts for display + let expected_change_str = if expected_change >= 0 { + format!("+{}", expected_change) + } else { + format!("{}", expected_change) + }; + let actual_change_str = if actual_change >= 0 { + format!("+{}", actual_change) + } else { + format!("{}", actual_change) + }; + + log_print!(" Expected change: {} planck", expected_change_str); + log_print!(" Actual change: {} planck", actual_change_str); + log_print!(""); + + // Allow some tolerance for transaction fees + let tolerance = (total_sent / 100).max(1_000_000_000_000); // 1% or 1 QNT minimum + + let diff = (actual_change - expected_change).unsigned_abs(); + if diff <= tolerance { + log_success!( + " {} Balance verification PASSED (within tolerance of {} planck)", + "✓".bright_green(), + tolerance + ); + } else { + log_print!( + " {} Balance verification: difference of {} planck (tolerance: {} planck)", + "!".bright_yellow(), + diff, + tolerance + ); + log_print!( + " Note: Transaction fees for {} initial transfers may account for the difference", + num_proofs + ); + } + log_print!(""); +} + +/// Run the multi-round wormhole flow +#[allow(clippy::too_many_arguments)] +async fn run_multiround( + num_proofs: usize, + rounds: usize, + amount: u128, + wallet_name: String, + password: Option, + password_file: Option, + keep_files: bool, + output_dir: String, + dry_run: bool, + node_url: &str, +) -> crate::error::Result<()> { + use colored::Colorize; + + log_print!(""); + log_print!("=================================================="); + log_print!(" Wormhole Multi-Round Flow Test"); + log_print!("=================================================="); + log_print!(""); + + // Validate parameters + validate_multiround_params(num_proofs, rounds)?; + + // Load wallet + let wallet = load_multiround_wallet(&wallet_name, password, password_file)?; + + // Create config struct + let config = + MultiroundConfig { num_proofs, rounds, amount, output_dir: output_dir.clone(), keep_files }; + + // Print configuration + print_multiround_config(&config, &wallet); + log_print!(" Dry run: {}", dry_run); + log_print!(""); // Create output directory std::fs::create_dir_all(&output_dir).map_err(|e| { @@ -1234,7 +1579,13 @@ async fn run_multiround( })?; if dry_run { - return run_multiround_dry_run(&mnemonic, num_proofs, rounds, amount, &wallet_address); + return run_multiround_dry_run( + &wallet.mnemonic, + num_proofs, + rounds, + amount, + &wallet.wallet_address, + ); } // Connect to node @@ -1248,7 +1599,7 @@ async fn run_multiround( log_verbose!("Minting account: {:?}", minting_account); // Record initial wallet balance for verification - let initial_balance = get_balance(&quantus_client, &wallet_address).await?; + let initial_balance = get_balance(&quantus_client, &wallet.wallet_address).await?; log_print!("{}", "Initial Balance:".bright_cyan()); log_print!(" Wallet balance: {} ({})", initial_balance, format_balance(initial_balance)); log_print!(""); @@ -1278,27 +1629,12 @@ async fn run_multiround( })?; // Derive secrets for this round - let pb = ProgressBar::new(num_proofs as u64); - pb.set_style( - ProgressStyle::default_bar() - .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") - .unwrap() - .progress_chars("#>-"), - ); - pb.set_message("Deriving secrets..."); - - let mut secrets: Vec = Vec::new(); - for i in 1..=num_proofs { - let secret = derive_wormhole_secret(&mnemonic, round, i)?; - secrets.push(secret); - pb.inc(1); - } - pb.finish_with_message("Secrets derived"); + let secrets = derive_round_secrets(&wallet.mnemonic, round, num_proofs)?; // Determine exit accounts let exit_accounts: Vec = if is_final { - log_print!("Final round - all proofs exit to wallet: {}", wallet_address); - vec![wallet_account_id.clone(); num_proofs] + log_print!("Final round - all proofs exit to wallet: {}", wallet.wallet_address); + vec![wallet.wallet_account_id.clone(); num_proofs] } else { log_print!( "Intermediate round - proofs exit to round {} wormhole addresses", @@ -1306,101 +1642,21 @@ async fn run_multiround( ); let mut addrs = Vec::new(); for i in 1..=num_proofs { - let next_secret = derive_wormhole_secret(&mnemonic, round + 1, i)?; + let next_secret = derive_wormhole_secret(&wallet.mnemonic, round + 1, i)?; addrs.push(SubxtAccountId(next_secret.address)); } addrs }; - // Step 1: Get transfer info + // Step 1: Get transfer info (execute transfers for round 1, reuse from previous round otherwise) if round == 1 { - log_print!("{}", "Step 1: Sending wormhole transfers from wallet...".bright_yellow()); - - // Randomly partition the total amount among proofs - // Minimum 1 DEV per proof to ensure meaningful amounts - let min_per_proof = SCALE_DOWN_FACTOR; // 0.01 DEV (minimum quantizable amount) - let partition_amounts = random_partition(amount, num_proofs, min_per_proof); - log_print!(" Random partition of {} ({}):", amount, format_balance(amount)); - for (i, &amt) in partition_amounts.iter().enumerate() { - log_print!(" Proof {}: {} ({})", i + 1, amt, format_balance(amt)); - } - - let pb = ProgressBar::new(num_proofs as u64); - pb.set_style( - ProgressStyle::default_bar() - .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") - .unwrap() - .progress_chars("#>-"), - ); - - current_transfers.clear(); - for (i, secret) in secrets.iter().enumerate() { - pb.set_message(format!("Transfer {}/{}", i + 1, num_proofs)); - - let wormhole_address = SubxtAccountId(secret.address); - let transfer_amount = partition_amounts[i]; - - // Submit transfer - let transfer_tx = quantus_node::api::tx().wormhole().transfer_native( - subxt::ext::subxt_core::utils::MultiAddress::Id(wormhole_address.clone()), - transfer_amount, - ); - - let quantum_keypair = QuantumKeyPair { - public_key: wallet_data.keypair.public_key.clone(), - private_key: wallet_data.keypair.private_key.clone(), - }; - - submit_transaction( - &quantus_client, - &quantum_keypair, - transfer_tx, - None, - ExecutionMode { finalized: false, wait_for_transaction: true }, - ) - .await - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Transfer failed: {}", e)) - })?; - - // Get the block and find our event - let block = at_best_block(&quantus_client).await.map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) - })?; - let block_hash = block.hash(); - - let events_api = client.events().at(block_hash).await.map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to get events: {}", e)) - })?; - - // Find our transfer event - let event = events_api - .find::() - .find(|e| if let Ok(evt) = e { evt.to.0 == secret.address } else { false }) - .ok_or_else(|| { - crate::error::QuantusError::Generic( - "No matching transfer event found".to_string(), - ) - })? - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Event decode error: {}", e)) - })?; - - let funding_account_bytes = wallet_data.keypair.to_account_id_32(); - current_transfers.push(TransferInfo { - block_hash, - transfer_count: event.transfer_count, - amount: transfer_amount, - wormhole_address, - funding_account: SubxtAccountId(funding_account_bytes.into()), - }); - - pb.inc(1); - } - pb.finish_with_message("Transfers complete"); + current_transfers = + execute_initial_transfers(&quantus_client, &wallet, &secrets, amount, num_proofs) + .await?; // Log balance immediately after funding transfers - let balance_after_funding = get_balance(&quantus_client, &wallet_address).await?; + let balance_after_funding = + get_balance(&quantus_client, &wallet.wallet_address).await?; let funding_deducted = initial_balance.saturating_sub(balance_after_funding); log_print!( " Balance after funding: {} ({}) [deducted: {} planck]", @@ -1410,92 +1666,19 @@ async fn run_multiround( ); } else { log_print!("{}", "Step 1: Using transfer info from previous round...".bright_yellow()); - // current_transfers was populated from the previous round's verification events - // The secrets for this round ARE the exit secrets from round-1 - // So current_transfers already has the right wormhole addresses log_print!(" Found {} transfer(s) from previous round", current_transfers.len()); } // Step 2: Generate proofs with random output partitioning - log_print!("{}", "Step 2: Generating proofs...".bright_yellow()); - - // All proofs in an aggregation batch must use the same block for storage proofs. - // Use the best block (which contains all transfers' state) for all proofs. - let proof_block = at_best_block(&quantus_client).await.map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) - })?; - let proof_block_hash = proof_block.hash(); - log_print!(" Using block {} for all proofs", hex::encode(proof_block_hash.0)); - - // Collect input amounts and exit accounts for random assignment - let input_amounts: Vec = current_transfers.iter().map(|t| t.amount).collect(); - let exit_account_bytes: Vec<[u8; 32]> = exit_accounts.iter().map(|a| a.0).collect(); - - // Compute random output assignments (each proof can have 2 outputs) - let output_assignments = - compute_random_output_assignments(&input_amounts, &exit_account_bytes, VOLUME_FEE_BPS); - - // Log the random partition - log_print!(" Random output partition:"); - for (i, assignment) in output_assignments.iter().enumerate() { - let amt1_planck = (assignment.output_amount_1 as u128) * SCALE_DOWN_FACTOR; - if assignment.output_amount_2 > 0 { - let amt2_planck = (assignment.output_amount_2 as u128) * SCALE_DOWN_FACTOR; - log_print!( - " Proof {}: {} ({}) -> 0x{}..., {} ({}) -> 0x{}...", - i + 1, - assignment.output_amount_1, - format_balance(amt1_planck), - hex::encode(&assignment.exit_account_1[..4]), - assignment.output_amount_2, - format_balance(amt2_planck), - hex::encode(&assignment.exit_account_2[..4]) - ); - } else { - log_print!( - " Proof {}: {} ({}) -> 0x{}...", - i + 1, - assignment.output_amount_1, - format_balance(amt1_planck), - hex::encode(&assignment.exit_account_1[..4]) - ); - } - } - - let pb = ProgressBar::new(num_proofs as u64); - pb.set_style( - ProgressStyle::default_bar() - .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") - .unwrap() - .progress_chars("#>-"), - ); - - let mut proof_files: Vec = Vec::new(); - for (i, (secret, transfer)) in secrets.iter().zip(current_transfers.iter()).enumerate() { - pb.set_message(format!("Proof {}/{}", i + 1, num_proofs)); - - let proof_file = format!("{}/proof_{}.hex", round_dir, i + 1); - - // Use the funding account from the transfer info - let funding_account_hex = format!("0x{}", hex::encode(transfer.funding_account.0)); - - // Generate proof with dual output assignment - generate_proof( - &hex::encode(secret.secret), - transfer.amount, // Use actual transfer amount for storage key - &output_assignments[i], - &format!("0x{}", hex::encode(proof_block_hash.0)), - transfer.transfer_count, - &funding_account_hex, - &proof_file, - &quantus_client, - ) - .await?; - - proof_files.push(proof_file); - pb.inc(1); - } - pb.finish_with_message("Proofs generated"); + let proof_files = generate_round_proofs( + &quantus_client, + &secrets, + ¤t_transfers, + &exit_accounts, + &round_dir, + num_proofs, + ) + .await?; // Step 3: Aggregate proofs log_print!("{}", "Step 3: Aggregating proofs...".bright_yellow()); @@ -1530,7 +1713,8 @@ async fn run_multiround( // Parse events to get transfer info for next round's wormhole addresses let next_round_addresses: Vec = (1..=num_proofs) .map(|i| { - let next_secret = derive_wormhole_secret(&mnemonic, round + 1, i).unwrap(); + let next_secret = + derive_wormhole_secret(&wallet.mnemonic, round + 1, i).unwrap(); SubxtAccountId(next_secret.address) }) .collect(); @@ -1550,7 +1734,7 @@ async fn run_multiround( } // Log balance after this round - let balance_after_round = get_balance(&quantus_client, &wallet_address).await?; + let balance_after_round = get_balance(&quantus_client, &wallet.wallet_address).await?; let change_from_initial = balance_after_round as i128 - initial_balance as i128; let change_str = if change_from_initial >= 0 { format!("+{}", change_from_initial) @@ -1577,74 +1761,8 @@ async fn run_multiround( log_print!(""); // Final balance verification - log_print!("{}", "Balance Verification:".bright_cyan()); - - // Query final balance - let final_balance = get_balance(&quantus_client, &wallet_address).await?; - - // Calculate expected balance change - // Total sent in round 1: the `amount` parameter is the total that was partitioned - let total_sent = amount; - - // Total received in final round: apply fee deduction for each round - let total_received = calculate_round_amount(amount, rounds); - - // Expected net change (may be negative due to fees) - let expected_change = total_received as i128 - total_sent as i128; - let actual_change = final_balance as i128 - initial_balance as i128; - - log_print!(" Initial balance: {} ({})", initial_balance, format_balance(initial_balance)); - log_print!(" Final balance: {} ({})", final_balance, format_balance(final_balance)); - log_print!(""); - log_print!(" Total sent (round 1): {} ({})", total_sent, format_balance(total_sent)); - log_print!( - " Total received (round {}): {} ({})", - rounds, - total_received, - format_balance(total_received) - ); - log_print!(""); - - // Format signed amounts for display - let expected_change_str = if expected_change >= 0 { - format!("+{}", expected_change) - } else { - format!("{}", expected_change) - }; - let actual_change_str = if actual_change >= 0 { - format!("+{}", actual_change) - } else { - format!("{}", actual_change) - }; - - log_print!(" Expected change: {} planck", expected_change_str); - log_print!(" Actual change: {} planck", actual_change_str); - log_print!(""); - - // Allow some tolerance for transaction fees (e.g., 1% or a fixed amount) - // The actual change may differ slightly due to transaction fees for the initial transfers - let tolerance = (total_sent / 100).max(1_000_000_000_000); // 1% or 1 QNT minimum - - let diff = (actual_change - expected_change).unsigned_abs(); - if diff <= tolerance { - log_success!( - " {} Balance verification PASSED (within tolerance of {} planck)", - "✓".bright_green(), - tolerance - ); - } else { - log_print!( - " {} Balance verification: difference of {} planck (tolerance: {} planck)", - "!".bright_yellow(), - diff, - tolerance - ); - log_print!( - " Note: Transaction fees for {} initial transfers may account for the difference", - num_proofs - ); - } - log_print!(""); + let final_balance = get_balance(&quantus_client, &wallet.wallet_address).await?; + verify_final_balance(initial_balance, final_balance, amount, rounds, num_proofs); if keep_files { log_print!("Proof files preserved in: {}", output_dir); @@ -2209,8 +2327,8 @@ mod tests { let output_medium = compute_output_amount(input_medium, VOLUME_FEE_BPS); assert_eq!(output_medium, 9990); assert!( - (output_medium as u64) * 10000 <= - (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) + (output_medium as u64) * 10000 + <= (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) ); // Large amounts near u32::MAX @@ -2295,8 +2413,8 @@ mod tests { let input_amount = inputs.private.input_amount; let output_amount = inputs.public.output_amount_1 + inputs.public.output_amount_2; assert!( - (output_amount as u64) * 10000 <= - (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), + (output_amount as u64) * 10000 + <= (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), "Test inputs violate fee constraint" ); From a652239ef622e11be62a5adf69b3c203a5782830 Mon Sep 17 00:00:00 2001 From: illuzen Date: Thu, 12 Feb 2026 17:43:39 +0800 Subject: [PATCH 09/26] fmt --- src/cli/wormhole.rs | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 75feb4c..a84522a 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -612,9 +612,8 @@ pub async fn handle_wormhole_command( node_url: &str, ) -> crate::error::Result<()> { match command { - WormholeCommands::Transfer { secret, amount, from, password, password_file } => { - submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await - }, + WormholeCommands::Transfer { secret, amount, from, password, password_file } => + submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await, WormholeCommands::Generate { secret, amount, @@ -659,15 +658,12 @@ pub async fn handle_wormhole_command( ) .await }, - WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => { - aggregate_proofs(proofs, output, depth, branching_factor).await - }, - WormholeCommands::VerifyAggregated { proof } => { - verify_aggregated_proof(proof, node_url).await - }, - WormholeCommands::ParseProof { proof, aggregated, verify } => { - parse_proof_file(proof, aggregated, verify).await - }, + WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => + aggregate_proofs(proofs, output, depth, branching_factor).await, + WormholeCommands::VerifyAggregated { proof } => + verify_aggregated_proof(proof, node_url).await, + WormholeCommands::ParseProof { proof, aggregated, verify } => + parse_proof_file(proof, aggregated, verify).await, WormholeCommands::Multiround { num_proofs, rounds, @@ -678,7 +674,7 @@ pub async fn handle_wormhole_command( keep_files, output_dir, dry_run, - } => { + } => run_multiround( num_proofs, rounds, @@ -691,8 +687,7 @@ pub async fn handle_wormhole_command( dry_run, node_url, ) - .await - }, + .await, } } @@ -1648,7 +1643,8 @@ async fn run_multiround( addrs }; - // Step 1: Get transfer info (execute transfers for round 1, reuse from previous round otherwise) + // Step 1: Get transfer info (execute transfers for round 1, reuse from previous round + // otherwise) if round == 1 { current_transfers = execute_initial_transfers(&quantus_client, &wallet, &secrets, amount, num_proofs) @@ -2327,8 +2323,8 @@ mod tests { let output_medium = compute_output_amount(input_medium, VOLUME_FEE_BPS); assert_eq!(output_medium, 9990); assert!( - (output_medium as u64) * 10000 - <= (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) + (output_medium as u64) * 10000 <= + (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) ); // Large amounts near u32::MAX @@ -2413,8 +2409,8 @@ mod tests { let input_amount = inputs.private.input_amount; let output_amount = inputs.public.output_amount_1 + inputs.public.output_amount_2; assert!( - (output_amount as u64) * 10000 - <= (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), + (output_amount as u64) * 10000 <= + (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), "Test inputs violate fee constraint" ); From 80d8571a9b54ead1bf0abace4f9eb62cae60ed35 Mon Sep 17 00:00:00 2001 From: illuzen Date: Thu, 12 Feb 2026 19:42:35 +0800 Subject: [PATCH 10/26] cleanup --- Cargo.lock | 2 + src/cli/mod.rs | 59 ++++++++- src/cli/wormhole.rs | 232 +++++++++++++++++----------------- tests/wormhole_integration.rs | 3 +- 4 files changed, 174 insertions(+), 122 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad34b2d..773f144 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4010,6 +4010,8 @@ dependencies = [ "qp-zk-circuits-common", "rand 0.8.5", "rayon", + "serde", + "serde_json", ] [[package]] diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 94c4ff1..ca7936f 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -249,6 +249,14 @@ pub enum DeveloperCommands { #[arg(long, default_value = "../chain")] chain_path: String, + /// Branching factor for aggregation tree (number of proofs aggregated at each level) + #[arg(long)] + branching_factor: usize, + + /// Depth of the aggregation tree (num_leaf_proofs = branching_factor^depth) + #[arg(long)] + depth: u32, + /// Skip copying to chain directory #[arg(long)] skip_chain: bool, @@ -476,8 +484,21 @@ pub async fn handle_developer_command(command: DeveloperCommands) -> crate::erro Ok(()) }, - DeveloperCommands::BuildCircuits { circuits_path, chain_path, skip_chain } => - build_wormhole_circuits(&circuits_path, &chain_path, skip_chain).await, + DeveloperCommands::BuildCircuits { + circuits_path, + chain_path, + branching_factor, + depth, + skip_chain, + } => + build_wormhole_circuits( + &circuits_path, + &chain_path, + branching_factor, + depth, + skip_chain, + ) + .await, } } @@ -485,11 +506,20 @@ pub async fn handle_developer_command(command: DeveloperCommands) -> crate::erro async fn build_wormhole_circuits( circuits_path: &str, chain_path: &str, + branching_factor: usize, + depth: u32, skip_chain: bool, ) -> crate::error::Result<()> { use std::{path::Path, process::Command}; + let num_leaf_proofs = branching_factor.pow(depth); log_print!("🔧 {} Building wormhole circuit binaries...", "DEVELOPER".bright_magenta().bold()); + log_print!( + " Configuration: branching_factor={}, depth={}, max_proofs={}", + branching_factor, + depth, + num_leaf_proofs + ); log_print!(""); let circuits_dir = Path::new(circuits_path); @@ -525,8 +555,11 @@ async fn build_wormhole_circuits( // Step 2: Run the circuit builder log_print!("⚡ Step 2: Running circuit builder (this may take a while)..."); let builder_path = circuits_dir.join("target/release/qp-wormhole-circuit-builder"); - let run_output = - Command::new(&builder_path).current_dir(circuits_dir).output().map_err(|e| { + let run_output = Command::new(&builder_path) + .args(["--branching-factor", &branching_factor.to_string(), "--depth", &depth.to_string()]) + .current_dir(circuits_dir) + .output() + .map_err(|e| { crate::error::QuantusError::Generic(format!("Failed to run circuit builder: {}", e)) })?; @@ -544,15 +577,17 @@ async fn build_wormhole_circuits( let source_bins = circuits_dir.join("generated-bins"); let cli_bins = Path::new("generated-bins"); - let bin_files = [ + // CLI needs prover.bin for proof generation + let cli_bin_files = [ "common.bin", "verifier.bin", "prover.bin", "aggregated_common.bin", "aggregated_verifier.bin", + "config.json", ]; - for file in &bin_files { + for file in &cli_bin_files { let src = source_bins.join(file); let dst = cli_bins.join(file); std::fs::copy(&src, &dst).map_err(|e| { @@ -570,7 +605,17 @@ async fn build_wormhole_circuits( log_error!(" Chain directory not found: {} (use --skip-chain to skip)", chain_path); } else { let chain_bins = chain_dir.join("pallets/wormhole"); - for file in &bin_files { + + // Chain only needs verifier binaries (no prover.bin - it's ~170MB and unused) + let chain_bin_files = [ + "common.bin", + "verifier.bin", + "aggregated_common.bin", + "aggregated_verifier.bin", + "config.json", + ]; + + for file in &chain_bin_files { let src = source_bins.join(file); let dst = chain_bins.join(file); std::fs::copy(&src, &dst).map_err(|e| { diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index a84522a..4f1ed22 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -56,6 +56,34 @@ pub const SCALE_DOWN_FACTOR: u128 = 10_000_000_000; /// This must match the on-chain VolumeFeeRateBps configuration pub const VOLUME_FEE_BPS: u32 = 10; +/// Aggregation config loaded from generated-bins/config.json +#[derive(Debug, Clone, serde::Deserialize)] +pub struct AggregationConfig { + pub branching_factor: usize, + pub depth: u32, + pub num_leaf_proofs: usize, +} + +impl AggregationConfig { + /// Load config from the generated-bins directory + pub fn load() -> crate::error::Result { + let config_path = Path::new("generated-bins/config.json"); + let config_str = std::fs::read_to_string(config_path).map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to read aggregation config from {}: {}. Run 'quantus developer build-circuits' first.", + config_path.display(), + e + )) + })?; + serde_json::from_str(&config_str).map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to parse aggregation config: {}", + e + )) + }) + } +} + /// Compute output amount after fee deduction /// output = input * (10000 - fee_bps) / 10000 pub fn compute_output_amount(input_amount: u32, fee_bps: u32) -> u32 { @@ -443,37 +471,6 @@ fn format_dispatch_error( } } -/// Validate aggregation parameters -pub fn validate_aggregation_params( - num_proofs: usize, - depth: usize, - branching_factor: usize, -) -> Result { - if num_proofs == 0 { - return Err("No proofs provided".to_string()); - } - - if branching_factor < 2 { - return Err("Branching factor must be at least 2".to_string()); - } - - if depth == 0 { - return Err("Depth must be at least 1".to_string()); - } - - // Calculate max leaf proofs for given depth and branching factor - let max_leaf_proofs = branching_factor.pow(depth as u32); - - if num_proofs > max_leaf_proofs { - return Err(format!( - "Too many proofs: {} provided, max {} for depth={} branching_factor={}", - num_proofs, max_leaf_proofs, depth, branching_factor - )); - } - - Ok(max_leaf_proofs) -} - #[derive(Subcommand, Debug)] pub enum WormholeCommands { /// Submit a wormhole transfer to an unspendable account @@ -537,15 +534,6 @@ pub enum WormholeCommands { /// Output file for the aggregated proof (default: aggregated_proof.hex) #[arg(short, long, default_value = "aggregated_proof.hex")] output: String, - - /// Tree depth for aggregation (default: 3, supports up to 8 proofs with - /// branching_factor=2) - #[arg(long, default_value = "3")] - depth: usize, - - /// Branching factor for aggregation tree (default: 2) - #[arg(long, default_value = "2")] - branching_factor: usize, }, /// Verify an aggregated wormhole proof on-chain VerifyAggregated { @@ -577,8 +565,8 @@ pub enum WormholeCommands { #[arg(short, long, default_value = "2")] rounds: usize, - /// Total amount in planck to partition across all proofs (default: 10 DEV) - #[arg(short, long, default_value = "10000000000000")] + /// Total amount in planck to partition across all proofs (default: 100 DEV) + #[arg(short, long, default_value = "100000000000000")] amount: u128, /// Wallet name to use for funding and final exit @@ -658,8 +646,7 @@ pub async fn handle_wormhole_command( ) .await }, - WormholeCommands::Aggregate { proofs, output, depth, branching_factor } => - aggregate_proofs(proofs, output, depth, branching_factor).await, + WormholeCommands::Aggregate { proofs, output } => aggregate_proofs(proofs, output).await, WormholeCommands::VerifyAggregated { proof } => verify_aggregated_proof(proof, node_url).await, WormholeCommands::ParseProof { proof, aggregated, verify } => @@ -806,45 +793,71 @@ async fn at_best_block( async fn aggregate_proofs( proof_files: Vec, output_file: String, - depth: usize, - branching_factor: usize, ) -> crate::error::Result<()> { - use qp_wormhole_aggregator::{ - aggregator::WormholeProofAggregator, circuits::tree::TreeAggregationConfig, - }; + use qp_wormhole_aggregator::aggregator::WormholeProofAggregator; use std::path::Path; log_print!("Aggregating {} proofs...", proof_files.len()); - // Validate aggregation parameters using helper function - let max_leaf_proofs = validate_aggregation_params(proof_files.len(), depth, branching_factor) - .map_err(crate::error::QuantusError::Generic)?; + // Load config first to validate and calculate padding needs + let bins_dir = Path::new("generated-bins"); + let agg_config = AggregationConfig::load()?; + + // Validate number of proofs before doing expensive work + if proof_files.len() > agg_config.num_leaf_proofs { + return Err(crate::error::QuantusError::Generic(format!( + "Too many proofs: {} provided, max {} supported by circuit", + proof_files.len(), + agg_config.num_leaf_proofs + ))); + } - // Configure aggregation - let aggregation_config = TreeAggregationConfig::new(branching_factor, depth as u32); + let num_padding_proofs = agg_config.num_leaf_proofs - proof_files.len(); - log_verbose!( - "Aggregation config: branching_factor={}, depth={}, num_leaf_proofs={}", - aggregation_config.tree_branching_factor, - aggregation_config.tree_depth, - max_leaf_proofs - ); + // Create progress bar for padding proof generation (if needed) + let progress_bar = if num_padding_proofs > 0 { + let pb = ProgressBar::new(num_padding_proofs as u64); + pb.set_style( + ProgressStyle::default_bar() + .template(" Generating {msg} [{bar:30}] {pos}/{len}") + .expect("Invalid progress bar template") + .progress_chars("=> "), + ); + pb.set_message(format!("{} padding proofs", num_padding_proofs)); + Some(pb) + } else { + None + }; - // Load aggregator from pre-built bins to ensure circuit digest matches on-chain verifier - let bins_dir = Path::new("generated-bins"); - let mut aggregator = WormholeProofAggregator::from_prebuilt_with_paths( - &bins_dir.join("prover.bin"), - &bins_dir.join("common.bin"), - &bins_dir.join("verifier.bin"), + // Load aggregator from pre-built bins (reads config from config.json) + // Only generates the padding proofs needed (num_leaf_proofs - num_real_proofs) + let mut aggregator = WormholeProofAggregator::from_prebuilt_dir( + bins_dir, + proof_files.len(), + Some(|current: usize, _total: usize| { + if let Some(ref pb) = progress_bar { + pb.set_position(current as u64); + } + }), ) .map_err(|e| { crate::error::QuantusError::Generic(format!( "Failed to load aggregator from pre-built bins: {}", e )) - })? - .with_config(aggregation_config); + })?; + + if let Some(pb) = progress_bar { + pb.finish_and_clear(); + } + + log_verbose!( + "Aggregation config: branching_factor={}, depth={}, num_leaf_proofs={}", + aggregator.config.tree_branching_factor, + aggregator.config.tree_depth, + aggregator.config.num_leaf_proofs + ); let common_data = aggregator.leaf_circuit_data.common.clone(); // Load and add proofs using helper function @@ -1052,11 +1065,6 @@ async fn verify_aggregated_proof(proof_file: String, node_url: &str) -> crate::e // Multi-round wormhole flow implementation // ============================================================================ -/// Aggregation config - hardcoded for now -const MULTIROUND_BRANCHING_FACTOR: usize = 2; -const MULTIROUND_DEPTH: usize = 3; -const MULTIROUND_MAX_PROOFS: usize = 8; // 2^3 - /// Information about a transfer needed for proof generation #[derive(Debug, Clone)] #[allow(dead_code)] @@ -1156,11 +1164,15 @@ struct MultiroundWalletContext { } /// Validate multiround parameters -fn validate_multiround_params(num_proofs: usize, rounds: usize) -> crate::error::Result<()> { - if !(1..=MULTIROUND_MAX_PROOFS).contains(&num_proofs) { +fn validate_multiround_params( + num_proofs: usize, + rounds: usize, + max_proofs: usize, +) -> crate::error::Result<()> { + if !(1..=max_proofs).contains(&num_proofs) { return Err(crate::error::QuantusError::Generic(format!( "num_proofs must be between 1 and {} (got: {})", - MULTIROUND_MAX_PROOFS, num_proofs + max_proofs, num_proofs ))); } if rounds < 1 { @@ -1213,7 +1225,11 @@ fn load_multiround_wallet( } /// Print multiround configuration summary -fn print_multiround_config(config: &MultiroundConfig, wallet: &MultiroundWalletContext) { +fn print_multiround_config( + config: &MultiroundConfig, + wallet: &MultiroundWalletContext, + agg_config: &AggregationConfig, +) { use colored::Colorize; log_print!("{}", "Configuration:".bright_cyan()); @@ -1229,8 +1245,8 @@ fn print_multiround_config(config: &MultiroundConfig, wallet: &MultiroundWalletC log_print!(" Rounds: {}", config.rounds); log_print!( " Aggregation: branching_factor={}, depth={}", - MULTIROUND_BRANCHING_FACTOR, - MULTIROUND_DEPTH + agg_config.branching_factor, + agg_config.depth ); log_print!(" Output directory: {}", config.output_dir); log_print!(" Keep files: {}", config.keep_files); @@ -1258,8 +1274,9 @@ async fn execute_initial_transfers( log_print!("{}", "Step 1: Sending wormhole transfers from wallet...".bright_yellow()); // Randomly partition the total amount among proofs - let min_per_proof = SCALE_DOWN_FACTOR; // 0.01 DEV (minimum quantizable amount) - let partition_amounts = random_partition(amount, num_proofs, min_per_proof); + // Each partition must meet the on-chain minimum transfer amount + // Minimum per partition is 0.02 DEV (2 quantized units) to ensure non-trivial amounts + let partition_amounts = random_partition(amount, num_proofs, 2 * SCALE_DOWN_FACTOR); log_print!(" Random partition of {} ({}):", amount, format_balance(amount)); for (i, &amt) in partition_amounts.iter().enumerate() { log_print!(" Proof {}: {} ({})", i + 1, amt, format_balance(amt)); @@ -1553,8 +1570,11 @@ async fn run_multiround( log_print!("=================================================="); log_print!(""); + // Load aggregation config from generated-bins/config.json + let agg_config = AggregationConfig::load()?; + // Validate parameters - validate_multiround_params(num_proofs, rounds)?; + validate_multiround_params(num_proofs, rounds, agg_config.num_leaf_proofs)?; // Load wallet let wallet = load_multiround_wallet(&wallet_name, password, password_file)?; @@ -1564,7 +1584,7 @@ async fn run_multiround( MultiroundConfig { num_proofs, rounds, amount, output_dir: output_dir.clone(), keep_files }; // Print configuration - print_multiround_config(&config, &wallet); + print_multiround_config(&config, &wallet, &agg_config); log_print!(" Dry run: {}", dry_run); log_print!(""); @@ -1680,13 +1700,7 @@ async fn run_multiround( log_print!("{}", "Step 3: Aggregating proofs...".bright_yellow()); let aggregated_file = format!("{}/aggregated.hex", round_dir); - aggregate_proofs( - proof_files, - aggregated_file.clone(), - MULTIROUND_DEPTH, - MULTIROUND_BRANCHING_FACTOR, - ) - .await?; + aggregate_proofs(proof_files, aggregated_file.clone()).await?; log_print!(" Aggregated proof saved to {}", aggregated_file); @@ -2137,8 +2151,7 @@ fn run_multiround_dry_run( // Show sample random partition for round 1 if round == 1 { - let min_per_proof = SCALE_DOWN_FACTOR; // 0.01 DEV (minimum quantizable amount) - let partition = random_partition(amount, num_proofs, min_per_proof); + let partition = random_partition(amount, num_proofs, 2 * SCALE_DOWN_FACTOR); log_print!(" Sample random partition (actual partition will differ):"); for (i, &amt) in partition.iter().enumerate() { log_print!(" Proof {}: {} ({})", i + 1, amt, format_balance(amt)); @@ -2264,21 +2277,6 @@ mod tests { .contains("too large")); } - #[test] - fn test_validate_aggregation_params() { - // Valid configurations - assert_eq!(validate_aggregation_params(2, 1, 2).unwrap(), 2); - assert_eq!(validate_aggregation_params(9, 2, 3).unwrap(), 9); // 3^2 = 9 - - // Invalid: no proofs, bad branching factor, zero depth - assert!(validate_aggregation_params(0, 1, 2).unwrap_err().contains("No proofs")); - assert!(validate_aggregation_params(2, 1, 1).unwrap_err().contains("Branching factor")); - assert!(validate_aggregation_params(2, 0, 2).unwrap_err().contains("Depth")); - - // Too many proofs for tree size - assert!(validate_aggregation_params(3, 1, 2).unwrap_err().contains("Too many proofs")); - } - #[test] fn test_proof_file_roundtrip() { let temp_file = NamedTempFile::new().unwrap(); @@ -2509,17 +2507,21 @@ mod tests { #[test] #[ignore] // This test is slow (~60s) - run with `cargo test -- --ignored` fn test_proof_aggregation() { - use qp_wormhole_aggregator::aggregator::WormholeProofAggregator; + use qp_wormhole_aggregator::{ + aggregator::WormholeProofAggregator, circuits::tree::TreeAggregationConfig, + }; let config = test_circuit_config(); + let aggregation_config = TreeAggregationConfig::new(2, 1); // branching_factor=2, depth=1 // Generate a proof let inputs = CircuitInputs::test_inputs_0(); let prover = WormholeProver::new(config.clone()); let proof = prover.commit(&inputs).unwrap().prove().unwrap(); - // Create aggregator with default config (branching_factor=2, depth=1) - let mut aggregator = WormholeProofAggregator::from_circuit_config(config); + // Create aggregator with explicit config + let mut aggregator = + WormholeProofAggregator::from_circuit_config(config, aggregation_config); // Add proof to aggregator aggregator.push_proof(proof.clone()).expect("Failed to push proof"); @@ -2559,9 +2561,12 @@ mod tests { #[test] #[ignore] // This test is very slow (~120s) - run with `cargo test -- --ignored` fn test_proof_aggregation_multiple_accounts() { - use qp_wormhole_aggregator::aggregator::WormholeProofAggregator; + use qp_wormhole_aggregator::{ + aggregator::WormholeProofAggregator, circuits::tree::TreeAggregationConfig, + }; let config = test_circuit_config(); + let aggregation_config = TreeAggregationConfig::new(2, 1); // branching_factor=2, depth=1 // Generate proofs with different inputs (different exit accounts) let inputs_0 = CircuitInputs::test_inputs_0(); @@ -2573,8 +2578,9 @@ mod tests { let prover_1 = WormholeProver::new(config.clone()); let proof_1 = prover_1.commit(&inputs_1).unwrap().prove().unwrap(); - // Create aggregator - let mut aggregator = WormholeProofAggregator::from_circuit_config(config); + // Create aggregator with explicit config + let mut aggregator = + WormholeProofAggregator::from_circuit_config(config, aggregation_config); // Add both proofs aggregator.push_proof(proof_0).expect("Failed to push proof 0"); diff --git a/tests/wormhole_integration.rs b/tests/wormhole_integration.rs index f048184..b0e33a9 100644 --- a/tests/wormhole_integration.rs +++ b/tests/wormhole_integration.rs @@ -525,8 +525,7 @@ fn aggregate_proofs( )); } - let mut aggregator = - WormholeProofAggregator::from_circuit_config(config).with_config(aggregation_config); + let mut aggregator = WormholeProofAggregator::from_circuit_config(config, aggregation_config); for (idx, ctx) in proof_contexts.into_iter().enumerate() { println!(" Adding proof {} to aggregator...", idx + 1); From 1bf27420d616c595353d7bcf99ae471e69b47046 Mon Sep 17 00:00:00 2001 From: illuzen Date: Thu, 12 Feb 2026 20:14:49 +0800 Subject: [PATCH 11/26] remove unused .bin files from copy list --- src/cli/mod.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index ca7936f..2a73f9d 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -606,14 +606,10 @@ async fn build_wormhole_circuits( } else { let chain_bins = chain_dir.join("pallets/wormhole"); - // Chain only needs verifier binaries (no prover.bin - it's ~170MB and unused) - let chain_bin_files = [ - "common.bin", - "verifier.bin", - "aggregated_common.bin", - "aggregated_verifier.bin", - "config.json", - ]; + // Chain only needs aggregated verifier binaries for verify_aggregated_proof + // (no prover.bin, and no single-proof verifier.bin/common.bin) + let chain_bin_files = + ["aggregated_common.bin", "aggregated_verifier.bin", "config.json"]; for file in &chain_bin_files { let src = source_bins.join(file); From fb2c787967732571c6c1a5160ce9ea1e4e59f3db Mon Sep 17 00:00:00 2001 From: illuzen Date: Fri, 13 Feb 2026 17:34:10 +0800 Subject: [PATCH 12/26] better circuit builder handling --- Cargo.lock | 1 + src/cli/mod.rs | 61 ++++++++++++++++------------ src/cli/wormhole.rs | 96 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 130 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 773f144..fdb7e1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4012,6 +4012,7 @@ dependencies = [ "rayon", "serde", "serde_json", + "sha2 0.10.9", ] [[package]] diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2a73f9d..12ad798 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -513,9 +513,8 @@ async fn build_wormhole_circuits( use std::{path::Path, process::Command}; let num_leaf_proofs = branching_factor.pow(depth); - log_print!("🔧 {} Building wormhole circuit binaries...", "DEVELOPER".bright_magenta().bold()); log_print!( - " Configuration: branching_factor={}, depth={}, max_proofs={}", + "🔧 Building ZK circuit binaries (branching_factor={}, depth={}, max_proofs={})", branching_factor, depth, num_leaf_proofs @@ -534,7 +533,7 @@ async fn build_wormhole_circuits( } // Step 1: Build the circuit builder - log_print!("📦 Step 1: Building circuit builder..."); + log_print!("Step 1/4: Building circuit builder..."); let build_output = Command::new("cargo") .args(["build", "--release", "-p", "qp-wormhole-circuit-builder"]) .current_dir(circuits_dir) @@ -550,10 +549,10 @@ async fn build_wormhole_circuits( stderr ))); } - log_success!(" Circuit builder compiled successfully"); + log_success!(" Done"); - // Step 2: Run the circuit builder - log_print!("⚡ Step 2: Running circuit builder (this may take a while)..."); + // Step 2: Run the circuit builder to generate binaries + log_print!("Step 2/4: Generating circuit binaries (this may take a while)..."); let builder_path = circuits_dir.join("target/release/qp-wormhole-circuit-builder"); let run_output = Command::new(&builder_path) .args(["--branching-factor", &branching_factor.to_string(), "--depth", &depth.to_string()]) @@ -570,14 +569,13 @@ async fn build_wormhole_circuits( stderr ))); } - log_success!(" Circuit binaries generated"); + log_success!(" Done"); - // Step 3: Copy binaries to CLI directory - log_print!("📋 Step 3: Copying binaries to CLI..."); + // Step 3: Copy binaries to CLI and touch aggregator to force recompile + log_print!("Step 3/4: Copying binaries to CLI..."); let source_bins = circuits_dir.join("generated-bins"); let cli_bins = Path::new("generated-bins"); - // CLI needs prover.bin for proof generation let cli_bin_files = [ "common.bin", "verifier.bin", @@ -593,21 +591,28 @@ async fn build_wormhole_circuits( std::fs::copy(&src, &dst).map_err(|e| { crate::error::QuantusError::Generic(format!("Failed to copy {} to CLI: {}", file, e)) })?; - log_verbose!(" Copied {} to CLI", file); + log_verbose!(" Copied {}", file); } - log_success!(" Binaries copied to CLI"); + + // Touch aggregator lib.rs to force cargo to recompile it + let aggregator_lib = circuits_dir.join("wormhole/aggregator/src/lib.rs"); + if aggregator_lib.exists() { + if let Ok(file) = std::fs::OpenOptions::new().write(true).open(&aggregator_lib) { + let _ = file.set_modified(std::time::SystemTime::now()); + } + } + log_success!(" Done"); // Step 4: Copy binaries to chain directory (if not skipped) if !skip_chain { - log_print!("📋 Step 4: Copying binaries to chain..."); + log_print!("Step 4/4: Copying binaries to chain..."); if !chain_dir.exists() { - log_error!(" Chain directory not found: {} (use --skip-chain to skip)", chain_path); + log_error!(" Chain directory not found: {}", chain_path); + log_print!(" Use --skip-chain to skip this step"); } else { let chain_bins = chain_dir.join("pallets/wormhole"); - // Chain only needs aggregated verifier binaries for verify_aggregated_proof - // (no prover.bin, and no single-proof verifier.bin/common.bin) let chain_bin_files = ["aggregated_common.bin", "aggregated_verifier.bin", "config.json"]; @@ -620,22 +625,30 @@ async fn build_wormhole_circuits( file, e )) })?; - log_verbose!(" Copied {} to chain", file); + log_verbose!(" Copied {}", file); + } + + // Touch pallet lib.rs to force cargo to recompile it + let pallet_lib = chain_bins.join("src/lib.rs"); + if pallet_lib.exists() { + if let Ok(file) = std::fs::OpenOptions::new().write(true).open(&pallet_lib) { + let _ = file.set_modified(std::time::SystemTime::now()); + } } - log_success!(" Binaries copied to chain"); + log_success!(" Done"); } } else { - log_print!("⏭️ Step 4: Skipping chain copy (--skip-chain)"); + log_print!("Step 4/4: Skipping chain copy (--skip-chain)"); } log_print!(""); - log_success!("🎉 Circuit build complete!"); + log_success!("Circuit build complete!"); log_print!(""); - log_print!("💡 {} Next steps:", "TIP".bright_blue().bold()); - log_print!(" 1. Rebuild the CLI: cargo build --release"); + log_print!("{}", "Next steps:".bright_blue().bold()); + log_print!(" 1. Rebuild CLI: cargo build --release"); if !skip_chain { - log_print!(" 2. Rebuild the chain: cd {} && cargo build --release", chain_path); - log_print!(" 3. Restart the chain node with the new binary"); + log_print!(" 2. Rebuild chain: cd {} && cargo build --release", chain_path); + log_print!(" 3. Restart the chain node"); } log_print!(""); diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 4f1ed22..b03e47c 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -56,17 +56,31 @@ pub const SCALE_DOWN_FACTOR: u128 = 10_000_000_000; /// This must match the on-chain VolumeFeeRateBps configuration pub const VOLUME_FEE_BPS: u32 = 10; -/// Aggregation config loaded from generated-bins/config.json +/// SHA256 hashes of circuit binary files for integrity verification. +/// Must match the BinaryHashes struct in qp-wormhole-aggregator/src/config.rs +#[derive(Debug, Clone, serde::Deserialize, Default)] +pub struct BinaryHashes { + pub common: Option, + pub verifier: Option, + pub prover: Option, + pub aggregated_common: Option, + pub aggregated_verifier: Option, +} + +/// Aggregation config loaded from generated-bins/config.json. +/// Must match the CircuitBinsConfig struct in qp-wormhole-aggregator/src/config.rs #[derive(Debug, Clone, serde::Deserialize)] pub struct AggregationConfig { pub branching_factor: usize, pub depth: u32, pub num_leaf_proofs: usize, + #[serde(default)] + pub hashes: Option, } impl AggregationConfig { /// Load config from the generated-bins directory - pub fn load() -> crate::error::Result { + pub fn load_from_bins() -> crate::error::Result { let config_path = Path::new("generated-bins/config.json"); let config_str = std::fs::read_to_string(config_path).map_err(|e| { crate::error::QuantusError::Generic(format!( @@ -82,6 +96,76 @@ impl AggregationConfig { )) }) } + + /// Verify that the binary files in generated-bins match the stored hashes. + pub fn verify_binary_hashes(&self) -> crate::error::Result<()> { + use sha2::{Digest, Sha256}; + + let Some(ref stored_hashes) = self.hashes else { + log_verbose!(" No hashes in config.json, skipping binary verification"); + return Ok(()); + }; + + let bins_dir = Path::new("generated-bins"); + let mut mismatches = Vec::new(); + + let hash_file = |filename: &str| -> Option { + let path = bins_dir.join(filename); + std::fs::read(&path).ok().map(|bytes| { + let hash = Sha256::digest(&bytes); + hex::encode(hash) + }) + }; + + if let Some(ref expected) = stored_hashes.aggregated_common { + if let Some(actual) = hash_file("aggregated_common.bin") { + if expected != &actual { + mismatches.push(format!( + "aggregated_common.bin: expected {}..., got {}...", + &expected[..16.min(expected.len())], + &actual[..16.min(actual.len())] + )); + } + } + } + + if let Some(ref expected) = stored_hashes.aggregated_verifier { + if let Some(actual) = hash_file("aggregated_verifier.bin") { + if expected != &actual { + mismatches.push(format!( + "aggregated_verifier.bin: expected {}..., got {}...", + &expected[..16.min(expected.len())], + &actual[..16.min(actual.len())] + )); + } + } + } + + if let Some(ref expected) = stored_hashes.prover { + if let Some(actual) = hash_file("prover.bin") { + if expected != &actual { + mismatches.push(format!( + "prover.bin: expected {}..., got {}...", + &expected[..16.min(expected.len())], + &actual[..16.min(actual.len())] + )); + } + } + } + + if mismatches.is_empty() { + log_verbose!(" Binary hashes verified successfully"); + Ok(()) + } else { + Err(crate::error::QuantusError::Generic(format!( + "Binary hash mismatch detected! The circuit binaries do not match config.json.\n\ + This can happen if binaries were regenerated but the CLI wasn't rebuilt.\n\ + Mismatches:\n {}\n\n\ + To fix: Run 'quantus developer build-circuits' and then 'cargo build --release'", + mismatches.join("\n ") + ))) + } + } } /// Compute output amount after fee deduction @@ -802,7 +886,11 @@ async fn aggregate_proofs( // Load config first to validate and calculate padding needs let bins_dir = Path::new("generated-bins"); - let agg_config = AggregationConfig::load()?; + let agg_config = AggregationConfig::load_from_bins()?; + + // Verify binary hashes match config.json to detect stale binaries + log_verbose!("Verifying circuit binary integrity..."); + agg_config.verify_binary_hashes()?; // Validate number of proofs before doing expensive work if proof_files.len() > agg_config.num_leaf_proofs { @@ -1571,7 +1659,7 @@ async fn run_multiround( log_print!(""); // Load aggregation config from generated-bins/config.json - let agg_config = AggregationConfig::load()?; + let agg_config = AggregationConfig::load_from_bins()?; // Validate parameters validate_multiround_params(num_proofs, rounds, agg_config.num_leaf_proofs)?; From a0f489b611c5e00e51f5a3bce36d2e99f0603e03 Mon Sep 17 00:00:00 2001 From: illuzen Date: Sun, 15 Feb 2026 16:25:03 +0800 Subject: [PATCH 13/26] make wormhole transfers just normal transfers --- README.md | 341 ++++++++++++++++++++++++++++++++++++++++++++ src/cli/mod.rs | 9 +- src/cli/wormhole.rs | 225 +++++++++-------------------- 3 files changed, 413 insertions(+), 162 deletions(-) diff --git a/README.md b/README.md index 8512f11..8c86085 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,347 @@ Common navigation patterns: +## Command Reference + +### Wormhole (Privacy-Preserving Transfers) + +The `wormhole` commands implement a ZK-proof-based privacy layer. Funds are sent to an unspendable account derived from a secret, a zero-knowledge proof is generated to prove ownership, and the proof is verified on-chain to mint equivalent tokens to an exit account -- breaking the on-chain link between sender and receiver. + +#### `quantus wormhole address` + +Derive the unspendable wormhole address from a secret. This is step one of a private transfer -- it shows the address you need to send funds to. + +```bash +quantus wormhole address --secret 0x<64-hex-chars> +``` + +Output: +``` +Wormhole Address + SS58: qDx... + Hex: 0x... + +To fund this address: + quantus send --from --to qDx... --amount +``` + +Then send funds using a standard transfer (the chain's `WormholeProofRecorderExtension` automatically records a transfer proof for any balance transfer): + +```bash +quantus send --from crystal_alice --to qDx... --amount 100 +``` + +#### `quantus wormhole prove` + +Generate a ZK proof for an existing wormhole transfer. The proof demonstrates knowledge of the secret without revealing it. + +```bash +quantus wormhole prove \ + --secret 0x \ + --amount 100000000000000 \ + --exit-account \ + --block 0x \ + --transfer-count \ + --funding-account 0x \ + --output proof.hex +``` + +- `--exit-account`: The destination address that will receive funds after on-chain verification (SS58 or `0x`-prefixed hex). +- `--block`: Block hash where the transfer was included. +- `--transfer-count`: Transfer count from the `NativeTransferred` event. +- `--output`: Output file path for the hex-encoded proof (default: `proof.hex`). + +#### `quantus wormhole aggregate` + +Aggregate multiple leaf proofs into a single recursive proof. The aggregation circuit pads with dummy proofs and shuffles to hide which slots are real. + +```bash +quantus wormhole aggregate \ + --proofs proof_1.hex proof_2.hex \ + --output aggregated_proof.hex +``` + +- `--proofs`: One or more hex-encoded proof files. The number must not exceed `num_leaf_proofs` from the circuit config. +- Before aggregation, the CLI verifies binary hashes from `generated-bins/config.json` to detect stale circuit binaries. +- Displays timing for dummy proof generation and aggregation separately. + +#### `quantus wormhole verify-aggregated` + +Submit an aggregated proof to the chain for on-chain verification. This is an unsigned extrinsic -- no wallet is needed. + +```bash +quantus wormhole verify-aggregated --proof aggregated_proof.hex +``` + +- On success, the chain mints tokens to each exit account listed in the proof. +- The command checks for `ProofVerified` and `ExtrinsicFailed` events and reports the result. + +#### `quantus wormhole parse-proof` + +Inspect the public inputs of a proof file for debugging. + +```bash +# Parse a leaf proof +quantus wormhole parse-proof --proof proof.hex + +# Parse an aggregated proof +quantus wormhole parse-proof --proof aggregated_proof.hex --aggregated + +# Parse and cryptographically verify locally +quantus wormhole parse-proof --proof aggregated_proof.hex --aggregated --verify +``` + +#### `quantus wormhole multiround` + +Run an automated multi-round wormhole flow: fund -> prove -> aggregate -> verify on-chain, repeated over multiple rounds. This is the primary integration test for the wormhole system. + +```bash +quantus wormhole multiround \ + --num-proofs 4 \ + --rounds 2 \ + --amount 100000000000000 \ + --wallet crystal_alice \ + --password "" \ + --keep-files \ + --output-dir /tmp/wormhole_test +``` + +- `--num-proofs`: Number of proofs per round (1 to `num_leaf_proofs` from circuit config, default: 2). +- `--rounds`: Number of rounds (default: 2). In intermediate rounds, exit accounts are the next round's wormhole addresses; in the final round, funds exit back to the wallet. +- `--amount`: Total amount in planck to randomly partition across proofs (default: 100 DEV). +- `--wallet`: Wallet name for funding (round 1) and final exit. +- `--keep-files`: Preserve proof files after completion (default: cleaned up). +- `--output-dir`: Directory for intermediate proof files (default: `/tmp/wormhole_multiround`). +- `--dry-run`: Show configuration and derived addresses without executing. + +Each round performs: +1. **Transfer** (round 1 only): Randomly partition the total amount and send to wormhole addresses derived via HD path `m/44'/189189189'/0'/'/'`. +2. **Generate proofs**: Create a ZK proof for each transfer with randomized dual-output assignments. +3. **Aggregate**: Combine all leaf proofs into a single recursive proof. +4. **Verify on-chain**: Submit the aggregated proof; the chain mints tokens to exit accounts. + +After all rounds, the command verifies the wallet balance matches expectations (initial - fees). + +--- + +### Developer Tools + +#### `quantus developer build-circuits` + +Build ZK circuit binaries from the `qp-zk-circuits` repository, then copy them to the CLI and chain directories. This is required whenever the circuit logic changes. + +```bash +quantus developer build-circuits \ + --branching-factor 2 \ + --depth 1 \ + --circuits-path ../qp-zk-circuits \ + --chain-path ../chain +``` + +- `--branching-factor`: Number of proofs aggregated at each tree level. +- `--depth`: Depth of the aggregation tree. Total leaf proofs = `branching_factor ^ depth`. +- `--circuits-path`: Path to the `qp-zk-circuits` repo (default: `../qp-zk-circuits`). +- `--chain-path`: Path to the chain repo (default: `../chain`). +- `--skip-chain`: Skip copying binaries to the chain directory. + +**What it does (4 steps):** +1. Builds the `qp-wormhole-circuit-builder` binary. +2. Runs the circuit builder to generate binary files in `generated-bins/` (includes `prover.bin`, `verifier.bin`, `common.bin`, `aggregated_verifier.bin`, `aggregated_common.bin`, `config.json` with SHA256 hashes). +3. Copies binaries to the CLI's `generated-bins/` directory and touches the aggregator source to force recompilation. +4. Copies chain-relevant binaries (`aggregated_common.bin`, `aggregated_verifier.bin`, `config.json`) to `chain/pallets/wormhole/` and touches the pallet source. + +After running, rebuild the chain (`cargo build --release` in the chain directory) so `include_bytes!()` picks up the new binaries. + +#### `quantus developer create-test-wallets` + +Create standard test wallets (`crystal_alice`, `crystal_bob`, `crystal_charlie`) with developer passwords for local testing. + +```bash +quantus developer create-test-wallets +``` + +--- + +### Wallet Management + +```bash +# Create a new quantum-safe wallet +quantus wallet create --name my_wallet + +# Create with explicit derivation path +quantus wallet create --name my_wallet --derivation-path "m/44'/189189'/0'/0/0" + +# Import from mnemonic +quantus wallet import --name recovered_wallet --mnemonic "word1 word2 ... word24" + +# Create from raw 32-byte seed +quantus wallet from-seed --name raw_wallet --seed <64-hex-chars> + +# List wallets +quantus wallet list + +# View wallet details +quantus wallet view --name my_wallet + +# Export mnemonic +quantus wallet export --name my_wallet --format mnemonic +``` + +--- + +### Sending Tokens + +```bash +# Simple transfer +quantus send --from crystal_alice --to
--amount 10.5 + +# With tip for priority +quantus send --from crystal_alice --to
--amount 10 --tip 0.1 + +# With manual nonce +quantus send --from crystal_alice --to
--amount 10 --nonce 42 +``` + +--- + +### Batch Transfers + +```bash +# From a JSON file +quantus batch send --from crystal_alice --batch-file transfers.json + +# Generate identical test transfers +quantus batch send --from crystal_alice --count 10 --to
--amount 1.0 + +# Check batch limits +quantus batch config --limits +``` + +--- + +### Reversible Transfers + +Schedule transfers with a time delay, allowing cancellation before execution. + +```bash +# Schedule with default delay +quantus reversible schedule-transfer --from alice --to bob --amount 10 + +# Schedule with custom delay +quantus reversible schedule-transfer-with-delay --from alice --to bob --amount 10 --delay 3600 + +# Cancel a pending transfer +quantus reversible cancel --tx-id 0x --from alice +``` + +--- + +### High-Security Mode + +Configure reversibility settings for an account (interceptor + delay). + +```bash +# Check status +quantus high-security status --account
+ +# Enable high-security with an interceptor +quantus high-security set --interceptor
--delay-seconds 3600 --from alice + +# Show accounts you guard +quantus high-security entrusted --from alice +``` + +--- + +### Account Recovery + +Social recovery using trusted friends. + +```bash +# Initiate recovery +quantus recovery initiate --rescuer bob --lost alice + +# Friend vouches +quantus recovery vouch --friend charlie --lost alice --rescuer bob + +# Claim after threshold met +quantus recovery claim --rescuer bob --lost alice +``` + +--- + +### Treasury + +```bash +# Check treasury balance +quantus treasury balance + +# Submit a spend proposal +quantus treasury submit-spend --beneficiary
--amount 100.0 --track small --from alice + +# Payout an approved spend +quantus treasury payout --index 0 --from alice +``` + +--- + +### Privacy-Preserving Transfer Queries + +Query transfers via a Subsquid indexer using hash-prefix queries that hide your exact address. + +```bash +quantus transfers query \ + --subsquid-url https://indexer.quantus.com/graphql \ + --prefix-len 4 \ + --wallet my_wallet +``` + +--- + +### Block Analysis + +```bash +# Analyze a specific block +quantus block analyze --number 1234 --all + +# Analyze latest block +quantus block analyze --latest --extrinsics --events + +# List blocks in a range +quantus block list --start 100 --end 110 +``` + +--- + +### Generic Pallet Calls + +Call any pallet function using metadata-driven parsing: + +```bash +quantus call \ + --pallet Balances \ + --call transfer_allow_death \ + --args '["5GrwvaEF...", "1000000000000"]' \ + --from crystal_alice +``` + +--- + +### Other Commands + +| Command | Description | +|---------|-------------| +| `quantus balance --address ` | Query account balance | +| `quantus events --block 123` | Query events from a block | +| `quantus events --finalized` | Events from the latest finalized block | +| `quantus system` | System information | +| `quantus system --runtime` | Runtime version details | +| `quantus metadata --pallet Balances` | Explore chain metadata | +| `quantus version` | CLI version | +| `quantus compatibility-check` | Check CLI/node compatibility | + +--- + ## 🔧 Environment Variables ### Password Management diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 12ad798..58c1cd2 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -644,13 +644,12 @@ async fn build_wormhole_circuits( log_print!(""); log_success!("Circuit build complete!"); log_print!(""); - log_print!("{}", "Next steps:".bright_blue().bold()); - log_print!(" 1. Rebuild CLI: cargo build --release"); if !skip_chain { - log_print!(" 2. Rebuild chain: cd {} && cargo build --release", chain_path); - log_print!(" 3. Restart the chain node"); + log_print!("{}", "Next steps:".bright_blue().bold()); + log_print!(" 1. Rebuild chain: cd {} && cargo build --release", chain_path); + log_print!(" 2. Restart the chain node"); + log_print!(""); } - log_print!(""); Ok(()) } diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index b03e47c..81e65a5 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -13,7 +13,6 @@ use crate::{ use clap::Subcommand; use indicatif::{ProgressBar, ProgressStyle}; use plonky2::plonk::proof::ProofWithPublicInputs; -use qp_poseidon::PoseidonHasher; use qp_rusty_crystals_hdwallet::{ derive_wormhole_from_mnemonic, generate_mnemonic, SensitiveBytes32, WormholePair, QUANTUS_WORMHOLE_CHAIN_ID, @@ -30,10 +29,7 @@ use qp_zk_circuits_common::{ utils::{digest_felts_to_bytes, BytesDigest}, }; use rand::RngCore; -use sp_core::{ - crypto::{AccountId32, Ss58Codec}, - Hasher, -}; +use sp_core::crypto::{AccountId32, Ss58Codec}; use std::path::Path; use subxt::{ backend::legacy::rpc_methods::ReadProof, @@ -60,8 +56,6 @@ pub const VOLUME_FEE_BPS: u32 = 10; /// Must match the BinaryHashes struct in qp-wormhole-aggregator/src/config.rs #[derive(Debug, Clone, serde::Deserialize, Default)] pub struct BinaryHashes { - pub common: Option, - pub verifier: Option, pub prover: Option, pub aggregated_common: Option, pub aggregated_verifier: Option, @@ -557,30 +551,14 @@ fn format_dispatch_error( #[derive(Subcommand, Debug)] pub enum WormholeCommands { - /// Submit a wormhole transfer to an unspendable account - Transfer { + /// Derive the unspendable wormhole address from a secret + Address { /// Secret (32-byte hex string) - used to derive the unspendable account #[arg(long)] secret: String, - - /// Amount to transfer - #[arg(long)] - amount: u128, - - /// Wallet name to fund from - #[arg(short, long)] - from: String, - - /// Password for the wallet - #[arg(short, long)] - password: Option, - - /// Read password from file - #[arg(long)] - password_file: Option, }, /// Generate a wormhole proof from an existing transfer - Generate { + Prove { /// Secret (32-byte hex string) used for the transfer #[arg(long)] secret: String, @@ -684,9 +662,8 @@ pub async fn handle_wormhole_command( node_url: &str, ) -> crate::error::Result<()> { match command { - WormholeCommands::Transfer { secret, amount, from, password, password_file } => - submit_wormhole_transfer(secret, amount, from, password, password_file, node_url).await, - WormholeCommands::Generate { + WormholeCommands::Address { secret } => show_wormhole_address(secret), + WormholeCommands::Prove { secret, amount, exit_account, @@ -718,6 +695,7 @@ pub async fn handle_wormhole_command( exit_account_2: [0u8; 32], }; + let prove_start = std::time::Instant::now(); generate_proof( &secret, amount, @@ -728,13 +706,18 @@ pub async fn handle_wormhole_command( &output, &quantus_client, ) - .await + .await?; + let prove_elapsed = prove_start.elapsed(); + log_print!("Proof generation: {:.2}s", prove_elapsed.as_secs_f64()); + Ok(()) }, WormholeCommands::Aggregate { proofs, output } => aggregate_proofs(proofs, output).await, - WormholeCommands::VerifyAggregated { proof } => - verify_aggregated_proof(proof, node_url).await, - WormholeCommands::ParseProof { proof, aggregated, verify } => - parse_proof_file(proof, aggregated, verify).await, + WormholeCommands::VerifyAggregated { proof } => { + verify_aggregated_proof(proof, node_url).await + }, + WormholeCommands::ParseProof { proof, aggregated, verify } => { + parse_proof_file(proof, aggregated, verify).await + }, WormholeCommands::Multiround { num_proofs, rounds, @@ -745,7 +728,7 @@ pub async fn handle_wormhole_command( keep_files, output_dir, dry_run, - } => + } => { run_multiround( num_proofs, rounds, @@ -758,42 +741,24 @@ pub async fn handle_wormhole_command( dry_run, node_url, ) - .await, + .await + }, } } pub type TransferProofKey = (u32, u64, AccountId32, AccountId32, u128); -/// Submit a wormhole transfer to an unspendable account -async fn submit_wormhole_transfer( - secret_hex: String, - funding_amount: u128, - from_wallet: String, - password: Option, - password_file: Option, - node_url: &str, -) -> crate::error::Result<()> { - log_print!("Submitting wormhole transfer..."); +/// Derive and display the unspendable wormhole address from a secret. +/// Users can then send funds to this address using `quantus send`. +fn show_wormhole_address(secret_hex: String) -> crate::error::Result<()> { + use colored::Colorize; - // Parse secret let secret_array = parse_secret_hex(&secret_hex).map_err(crate::error::QuantusError::Generic)?; let secret: BytesDigest = secret_array.try_into().map_err(|e| { crate::error::QuantusError::Generic(format!("Failed to convert secret: {:?}", e)) })?; - // Load keypair - let keypair = crate::wallet::load_keypair_from_wallet(&from_wallet, password, password_file)?; - - // Connect to node - let quantus_client = QuantusClient::new(node_url) - .await - .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to connect: {}", e)))?; - let client = quantus_client.client(); - - let funding_account = AccountId32::new(PoseidonHasher::hash(keypair.public_key.as_ref()).0); - - // Generate unspendable account from secret let unspendable_account = qp_wormhole_circuit::unspendable_account::UnspendableAccount::from_secret(secret) .account_id; @@ -803,65 +768,17 @@ async fn submit_wormhole_transfer( .as_ref() .try_into() .expect("BytesDigest is always 32 bytes"); - let unspendable_account_id = SubxtAccountId(unspendable_account_bytes); - - log_verbose!("Funding account: 0x{}", hex::encode(funding_account.as_ref() as &[u8])); - log_verbose!("Unspendable account: 0x{}", hex::encode(unspendable_account_bytes)); - // Transfer to unspendable account - let transfer_tx = quantus_node::api::tx().wormhole().transfer_native( - subxt::ext::subxt_core::utils::MultiAddress::Id(unspendable_account_id.clone()), - funding_amount, - ); - - let quantum_keypair = QuantumKeyPair { - public_key: keypair.public_key.clone(), - private_key: keypair.private_key.clone(), - }; - - submit_transaction( - &quantus_client, - &quantum_keypair, - transfer_tx, - None, - ExecutionMode { finalized: false, wait_for_transaction: true }, - ) - .await - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - - // Get block and event details - let blocks = at_best_block(&quantus_client) - .await - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - let block_hash = blocks.hash(); + let account_id = sp_core::crypto::AccountId32::new(unspendable_account_bytes); + let ss58_address = + account_id.to_ss58check_with_version(sp_core::crypto::Ss58AddressFormat::custom(189)); - let events_api = client - .events() - .at(block_hash) - .await - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - - // Find our specific transfer event - let event = events_api - .find::() - .find(|e| if let Ok(evt) = e { evt.to.0 == unspendable_account_bytes } else { false }) - .ok_or_else(|| { - crate::error::QuantusError::Generic( - "No matching NativeTransferred event found".to_string(), - ) - })? - .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?; - - // Output all the details needed for proof generation - log_success!("Transfer successful!"); - log_success!("Block: {:?}", block_hash); + log_print!("{}", "Wormhole Address".bright_cyan()); + log_print!(" SS58: {}", ss58_address.bright_green()); + log_print!(" Hex: 0x{}", hex::encode(unspendable_account_bytes)); log_print!(""); - log_print!("Use these values for proof generation:"); - log_print!(" --secret {}", secret_hex); - log_print!(" --amount {}", funding_amount); - log_print!(" --block 0x{}", hex::encode(block_hash.as_ref())); - log_print!(" --transfer-count {}", event.transfer_count); - log_print!(" --funding-account 0x{}", hex::encode(funding_account.as_ref() as &[u8])); + log_print!("To fund this address:"); + log_print!(" quantus send --from --to {} --amount ", ss58_address); Ok(()) } @@ -904,41 +821,17 @@ async fn aggregate_proofs( let num_padding_proofs = agg_config.num_leaf_proofs - proof_files.len(); // Create progress bar for padding proof generation (if needed) - let progress_bar = if num_padding_proofs > 0 { - let pb = ProgressBar::new(num_padding_proofs as u64); - pb.set_style( - ProgressStyle::default_bar() - .template(" Generating {msg} [{bar:30}] {pos}/{len}") - .expect("Invalid progress bar template") - .progress_chars("=> "), - ); - pb.set_message(format!("{} padding proofs", num_padding_proofs)); - Some(pb) - } else { - None - }; - // Load aggregator from pre-built bins (reads config from config.json) - // Only generates the padding proofs needed (num_leaf_proofs - num_real_proofs) - let mut aggregator = WormholeProofAggregator::from_prebuilt_dir( - bins_dir, - proof_files.len(), - Some(|current: usize, _total: usize| { - if let Some(ref pb) = progress_bar { - pb.set_position(current as u64); - } - }), - ) - .map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to load aggregator from pre-built bins: {}", - e - )) - })?; + // This also generates the padding (dummy) proofs needed + log_print!(" Loading aggregator and generating {} dummy proofs...", num_padding_proofs); - if let Some(pb) = progress_bar { - pb.finish_and_clear(); - } + let mut aggregator = WormholeProofAggregator::from_prebuilt_dir(bins_dir, proof_files.len()) + .map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to load aggregator from pre-built bins: {}", + e + )) + })?; log_verbose!( "Aggregation config: branching_factor={}, depth={}, num_leaf_proofs={}", @@ -969,10 +862,13 @@ async fn aggregate_proofs( })?; } - log_print!("Running aggregation..."); + log_print!(" Running aggregation..."); + let agg_start = std::time::Instant::now(); let aggregated_proof = aggregator .aggregate() .map_err(|e| crate::error::QuantusError::Generic(format!("Aggregation failed: {}", e)))?; + let agg_elapsed = agg_start.elapsed(); + log_print!(" Aggregation: {:.2}s", agg_elapsed.as_secs_f64()); // Parse and display aggregated public inputs let aggregated_public_inputs = AggregatedPublicCircuitInputs::try_from_felts( @@ -1359,7 +1255,7 @@ async fn execute_initial_transfers( ) -> crate::error::Result> { use colored::Colorize; - log_print!("{}", "Step 1: Sending wormhole transfers from wallet...".bright_yellow()); + log_print!("{}", "Step 1: Sending transfers to wormhole addresses...".bright_yellow()); // Randomly partition the total amount among proofs // Each partition must meet the on-chain minimum transfer amount @@ -1387,8 +1283,10 @@ async fn execute_initial_transfers( let wormhole_address = SubxtAccountId(secret.address); let transfer_amount = partition_amounts[i]; - // Submit transfer - let transfer_tx = quantus_node::api::tx().wormhole().transfer_native( + // Use standard Balances::transfer_allow_death -- the chain's + // WormholeProofRecorderExtension automatically records a transfer proof + // and emits NativeTransferred for any balance transfer. + let transfer_tx = quantus_node::api::tx().balances().transfer_allow_death( subxt::ext::subxt_core::utils::MultiAddress::Id(wormhole_address.clone()), transfer_amount, ); @@ -1418,7 +1316,7 @@ async fn execute_initial_transfers( crate::error::QuantusError::Generic(format!("Failed to get events: {}", e)) })?; - // Find our transfer event + // Find the NativeTransferred event emitted by the WormholeProofRecorderExtension let event = events_api .find::() .find(|e| if let Ok(evt) = e { evt.to.0 == secret.address } else { false }) @@ -1508,6 +1406,7 @@ async fn generate_round_proofs( .progress_chars("#>-"), ); + let proof_gen_start = std::time::Instant::now(); let mut proof_files = Vec::new(); for (i, (secret, transfer)) in secrets.iter().zip(transfers.iter()).enumerate() { pb.set_message(format!("Proof {}/{}", i + 1, num_proofs)); @@ -1517,6 +1416,8 @@ async fn generate_round_proofs( // Use the funding account from the transfer info let funding_account_hex = format!("0x{}", hex::encode(transfer.funding_account.0)); + let single_start = std::time::Instant::now(); + // Generate proof with dual output assignment generate_proof( &hex::encode(secret.secret), @@ -1530,10 +1431,20 @@ async fn generate_round_proofs( ) .await?; + let single_elapsed = single_start.elapsed(); + log_verbose!(" Proof {} generated in {:.2}s", i + 1, single_elapsed.as_secs_f64()); + proof_files.push(proof_file); pb.inc(1); } pb.finish_with_message("Proofs generated"); + let proof_gen_elapsed = proof_gen_start.elapsed(); + log_print!( + " Proof generation: {:.2}s ({} proofs, {:.2}s avg)", + proof_gen_elapsed.as_secs_f64(), + num_proofs, + proof_gen_elapsed.as_secs_f64() / num_proofs as f64, + ); Ok(proof_files) } @@ -2409,8 +2320,8 @@ mod tests { let output_medium = compute_output_amount(input_medium, VOLUME_FEE_BPS); assert_eq!(output_medium, 9990); assert!( - (output_medium as u64) * 10000 <= - (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) + (output_medium as u64) * 10000 + <= (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) ); // Large amounts near u32::MAX @@ -2495,8 +2406,8 @@ mod tests { let input_amount = inputs.private.input_amount; let output_amount = inputs.public.output_amount_1 + inputs.public.output_amount_2; assert!( - (output_amount as u64) * 10000 <= - (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), + (output_amount as u64) * 10000 + <= (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), "Test inputs violate fee constraint" ); From 49d73ce45faae3aad99b7126cb68c64a21be22ba Mon Sep 17 00:00:00 2001 From: illuzen Date: Sun, 15 Feb 2026 21:49:31 +0800 Subject: [PATCH 14/26] no local deps --- Cargo.lock | 92 ++++++++++++++++++++++++++++++++++++++++-------------- Cargo.toml | 23 +++++--------- 2 files changed, 76 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdb7e1b..274d98b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3999,15 +3999,17 @@ dependencies = [ [[package]] name = "qp-wormhole-aggregator" -version = "1.0.1" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128197d45244b09c2a74e7741dc738e99ec9e6e962e130141cfb5a039d90a05c" dependencies = [ "anyhow", "hex", "qp-plonky2", - "qp-wormhole-circuit", - "qp-wormhole-inputs", + "qp-wormhole-circuit 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "qp-wormhole-prover", - "qp-zk-circuits-common", + "qp-zk-circuits-common 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.8.5", "rayon", "serde", @@ -4017,51 +4019,94 @@ dependencies = [ [[package]] name = "qp-wormhole-circuit" -version = "1.0.1" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d07dc178b68cb1ba21afe953d42a9f3c35aac2da88452d15f6bc6d5354ff665" dependencies = [ "anyhow", "hex", "qp-plonky2", - "qp-wormhole-inputs", - "qp-zk-circuits-common", + "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-zk-circuits-common 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "qp-wormhole-circuit" +version = "1.0.5" +source = "git+https://github.com/Quantus-Network/qp-zk-circuits.git#8627990c07cf7115e01a09298265fef31cc1f18c" +dependencies = [ + "anyhow", + "hex", + "qp-plonky2", + "qp-wormhole-inputs 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", + "qp-zk-circuits-common 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", ] [[package]] name = "qp-wormhole-inputs" -version = "1.0.1" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed52f1c97996071aa3442537e6cd34a964568d7cec3dfd2a19c008aefc65a69" +dependencies = [ + "anyhow", +] + +[[package]] +name = "qp-wormhole-inputs" +version = "1.0.5" +source = "git+https://github.com/Quantus-Network/qp-zk-circuits.git#8627990c07cf7115e01a09298265fef31cc1f18c" dependencies = [ "anyhow", ] [[package]] name = "qp-wormhole-prover" -version = "1.0.1" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ae4a1eaa8549ac5471b39aa48325ad645bf0b446985606719f6dd4f67e87f08" dependencies = [ "anyhow", "qp-plonky2", - "qp-wormhole-circuit", - "qp-wormhole-inputs", - "qp-zk-circuits-common", + "qp-wormhole-circuit 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-zk-circuits-common 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "qp-wormhole-verifier" -version = "1.0.1" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391aa040d915295504bd2675be8d140fcbb639dbfe7fe033de604169c185d7f6" dependencies = [ "anyhow", "qp-plonky2-verifier", - "qp-wormhole-inputs", + "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "qp-zk-circuits-common" -version = "1.0.1" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8259c977a1f275fe4c56a85b8bca4d23a4909cbf30601d850380672a58a4bf5c" +dependencies = [ + "anyhow", + "hex", + "qp-plonky2", + "qp-poseidon-core", + "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", +] + +[[package]] +name = "qp-zk-circuits-common" +version = "1.0.5" +source = "git+https://github.com/Quantus-Network/qp-zk-circuits.git#8627990c07cf7115e01a09298265fef31cc1f18c" dependencies = [ "anyhow", "hex", "qp-plonky2", "qp-poseidon-core", - "qp-wormhole-inputs", + "qp-wormhole-inputs 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", "serde", ] @@ -4089,11 +4134,11 @@ dependencies = [ "qp-rusty-crystals-dilithium", "qp-rusty-crystals-hdwallet", "qp-wormhole-aggregator", - "qp-wormhole-circuit", - "qp-wormhole-inputs", + "qp-wormhole-circuit 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "qp-wormhole-prover", "qp-wormhole-verifier", - "qp-zk-circuits-common", + "qp-zk-circuits-common 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.9.2", "reqwest", "rpassword", @@ -5980,14 +6025,15 @@ dependencies = [ [[package]] name = "test-helpers" -version = "1.0.1" +version = "1.0.5" +source = "git+https://github.com/Quantus-Network/qp-zk-circuits.git#8627990c07cf7115e01a09298265fef31cc1f18c" dependencies = [ "anyhow", "hex", "qp-plonky2", - "qp-wormhole-circuit", - "qp-wormhole-inputs", - "qp-zk-circuits-common", + "qp-wormhole-circuit 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", + "qp-wormhole-inputs 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", + "qp-zk-circuits-common 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index cd6b34a..0b9ba78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,27 +76,18 @@ subxt-metadata = "0.43.0" # ZK proof generation anyhow = "1.0" -qp-wormhole-circuit = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-circuit", default-features = false, features = ["std"] } -qp-wormhole-prover = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-prover", default-features = false, features = ["std"] } -qp-wormhole-verifier = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-verifier", default-features = false, features = ["std"] } -qp-wormhole-aggregator = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-aggregator", default-features = false, features = ["rayon", "std"] } -qp-wormhole-inputs = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-wormhole-inputs", default-features = false, features = ["std"] } -qp-zk-circuits-common = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "qp-zk-circuits-common", default-features = false, features = ["std"] } +qp-wormhole-circuit = { version = "1.0.5", default-features = false, features = ["std"] } +qp-wormhole-prover = { version = "1.0.5", default-features = false, features = ["std"] } +qp-wormhole-verifier = { version = "1.0.5", default-features = false, features = ["std"] } +qp-wormhole-aggregator = { version = "1.0.5", default-features = false, features = ["rayon", "std"] } +qp-wormhole-inputs = { version = "1.0.5", default-features = false, features = ["std"] } +qp-zk-circuits-common = { version = "1.0.5", default-features = false, features = ["std"] } qp-plonky2 = { version = "1.1.3", default-features = false, features = ["rand", "std"] } [dev-dependencies] tempfile = "3.8" serial_test = "3.1" -qp-wormhole-test-helpers = { git = "https://github.com/Quantus-Network/qp-zk-circuits", branch = "illuzen/agg-fees", package = "test-helpers" } - -[patch."https://github.com/Quantus-Network/qp-zk-circuits"] -qp-wormhole-circuit = { path = "../qp-zk-circuits/wormhole/circuit" } -qp-wormhole-prover = { path = "../qp-zk-circuits/wormhole/prover" } -qp-wormhole-verifier = { path = "../qp-zk-circuits/wormhole/verifier" } -qp-wormhole-aggregator = { path = "../qp-zk-circuits/wormhole/aggregator" } -qp-wormhole-inputs = { path = "../qp-zk-circuits/wormhole/inputs" } -qp-zk-circuits-common = { path = "../qp-zk-circuits/common" } -test-helpers = { path = "../qp-zk-circuits/wormhole/tests/test-helpers" } +test-helpers = { git = "https://github.com/Quantus-Network/qp-zk-circuits.git" } [patch.crates-io] qp-dilithium-crypto = { path = "../chain/primitives/dilithium-crypto" } From 22a629e6d90dfce27c5b0900b27553c7e7bb8c4f Mon Sep 17 00:00:00 2001 From: illuzen Date: Sun, 15 Feb 2026 21:51:53 +0800 Subject: [PATCH 15/26] fmt --- src/cli/wormhole.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 81e65a5..52b565c 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -712,12 +712,10 @@ pub async fn handle_wormhole_command( Ok(()) }, WormholeCommands::Aggregate { proofs, output } => aggregate_proofs(proofs, output).await, - WormholeCommands::VerifyAggregated { proof } => { - verify_aggregated_proof(proof, node_url).await - }, - WormholeCommands::ParseProof { proof, aggregated, verify } => { - parse_proof_file(proof, aggregated, verify).await - }, + WormholeCommands::VerifyAggregated { proof } => + verify_aggregated_proof(proof, node_url).await, + WormholeCommands::ParseProof { proof, aggregated, verify } => + parse_proof_file(proof, aggregated, verify).await, WormholeCommands::Multiround { num_proofs, rounds, @@ -728,7 +726,7 @@ pub async fn handle_wormhole_command( keep_files, output_dir, dry_run, - } => { + } => run_multiround( num_proofs, rounds, @@ -741,8 +739,7 @@ pub async fn handle_wormhole_command( dry_run, node_url, ) - .await - }, + .await, } } @@ -2320,8 +2317,8 @@ mod tests { let output_medium = compute_output_amount(input_medium, VOLUME_FEE_BPS); assert_eq!(output_medium, 9990); assert!( - (output_medium as u64) * 10000 - <= (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) + (output_medium as u64) * 10000 <= + (input_medium as u64) * (10000 - VOLUME_FEE_BPS as u64) ); // Large amounts near u32::MAX @@ -2406,8 +2403,8 @@ mod tests { let input_amount = inputs.private.input_amount; let output_amount = inputs.public.output_amount_1 + inputs.public.output_amount_2; assert!( - (output_amount as u64) * 10000 - <= (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), + (output_amount as u64) * 10000 <= + (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), "Test inputs violate fee constraint" ); From bb419bdebf5281a39f7e4d380cc75250421a9987 Mon Sep 17 00:00:00 2001 From: illuzen Date: Sun, 15 Feb 2026 22:55:30 +0800 Subject: [PATCH 16/26] clippy --- Cargo.lock | 80 +++------------ Cargo.toml | 1 - src/cli/wormhole.rs | 243 +------------------------------------------- 3 files changed, 16 insertions(+), 308 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 274d98b..c0f46e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2156,7 +2156,6 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", - "rayon", "serde", ] @@ -3565,9 +3564,6 @@ name = "plonky2_maybe_rayon" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1e554181dc95243b8d9948ae7bae5759c7fb2502fed28f671f95ef38079406" -dependencies = [ - "rayon", -] [[package]] name = "plonky2_util" @@ -3826,7 +3822,6 @@ checksum = "593bccf15b8e2f9eb904ef4010f68b81ddcceb70aaf90116ce29ec09d7578dd4" dependencies = [ "ahash", "anyhow", - "getrandom 0.2.17", "hashbrown 0.14.5", "itertools 0.11.0", "keccak-hash 0.8.0", @@ -3843,11 +3838,9 @@ dependencies = [ "qp-plonky2-verifier", "qp-poseidon-constants", "rand 0.8.5", - "rand_chacha 0.3.1", "serde", "static_assertions", "unroll", - "web-time", ] [[package]] @@ -4006,10 +3999,10 @@ dependencies = [ "anyhow", "hex", "qp-plonky2", - "qp-wormhole-circuit 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-wormhole-circuit", + "qp-wormhole-inputs", "qp-wormhole-prover", - "qp-zk-circuits-common 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-zk-circuits-common", "rand 0.8.5", "rayon", "serde", @@ -4026,20 +4019,8 @@ dependencies = [ "anyhow", "hex", "qp-plonky2", - "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "qp-zk-circuits-common 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "qp-wormhole-circuit" -version = "1.0.5" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits.git#8627990c07cf7115e01a09298265fef31cc1f18c" -dependencies = [ - "anyhow", - "hex", - "qp-plonky2", - "qp-wormhole-inputs 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", - "qp-zk-circuits-common 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", + "qp-wormhole-inputs", + "qp-zk-circuits-common", ] [[package]] @@ -4051,14 +4032,6 @@ dependencies = [ "anyhow", ] -[[package]] -name = "qp-wormhole-inputs" -version = "1.0.5" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits.git#8627990c07cf7115e01a09298265fef31cc1f18c" -dependencies = [ - "anyhow", -] - [[package]] name = "qp-wormhole-prover" version = "1.0.5" @@ -4067,9 +4040,9 @@ checksum = "6ae4a1eaa8549ac5471b39aa48325ad645bf0b446985606719f6dd4f67e87f08" dependencies = [ "anyhow", "qp-plonky2", - "qp-wormhole-circuit 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "qp-zk-circuits-common 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-wormhole-circuit", + "qp-wormhole-inputs", + "qp-zk-circuits-common", ] [[package]] @@ -4080,7 +4053,7 @@ checksum = "391aa040d915295504bd2675be8d140fcbb639dbfe7fe033de604169c185d7f6" dependencies = [ "anyhow", "qp-plonky2-verifier", - "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-wormhole-inputs", ] [[package]] @@ -4093,20 +4066,7 @@ dependencies = [ "hex", "qp-plonky2", "qp-poseidon-core", - "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde", -] - -[[package]] -name = "qp-zk-circuits-common" -version = "1.0.5" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits.git#8627990c07cf7115e01a09298265fef31cc1f18c" -dependencies = [ - "anyhow", - "hex", - "qp-plonky2", - "qp-poseidon-core", - "qp-wormhole-inputs 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", + "qp-wormhole-inputs", "serde", ] @@ -4134,11 +4094,11 @@ dependencies = [ "qp-rusty-crystals-dilithium", "qp-rusty-crystals-hdwallet", "qp-wormhole-aggregator", - "qp-wormhole-circuit 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "qp-wormhole-inputs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-wormhole-circuit", + "qp-wormhole-inputs", "qp-wormhole-prover", "qp-wormhole-verifier", - "qp-zk-circuits-common 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "qp-zk-circuits-common", "rand 0.9.2", "reqwest", "rpassword", @@ -4151,7 +4111,6 @@ dependencies = [ "subxt", "subxt-metadata", "tempfile", - "test-helpers", "thiserror 2.0.18", "tokio", "toml 0.9.12+spec-1.1.0", @@ -6023,19 +5982,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "test-helpers" -version = "1.0.5" -source = "git+https://github.com/Quantus-Network/qp-zk-circuits.git#8627990c07cf7115e01a09298265fef31cc1f18c" -dependencies = [ - "anyhow", - "hex", - "qp-plonky2", - "qp-wormhole-circuit 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", - "qp-wormhole-inputs 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", - "qp-zk-circuits-common 1.0.5 (git+https://github.com/Quantus-Network/qp-zk-circuits.git)", -] - [[package]] name = "thiserror" version = "1.0.69" diff --git a/Cargo.toml b/Cargo.toml index 0b9ba78..da6bd41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,7 +87,6 @@ qp-plonky2 = { version = "1.1.3", default-features = false, features = ["rand", [dev-dependencies] tempfile = "3.8" serial_test = "3.1" -test-helpers = { git = "https://github.com/Quantus-Network/qp-zk-circuits.git" } [patch.crates-io] qp-dilithium-crypto = { path = "../chain/primitives/dilithium-crypto" } diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 52b565c..8c2c45d 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -2188,26 +2188,8 @@ fn run_multiround_dry_run( #[cfg(test)] mod tests { use super::*; - use plonky2::plonk::circuit_data::CircuitConfig; - use qp_wormhole_circuit::inputs::{CircuitInputs, ParsePublicInputs}; - use qp_wormhole_inputs::{AggregatedPublicCircuitInputs, PublicCircuitInputs}; - use qp_wormhole_prover::WormholeProver; - use qp_wormhole_test_helpers::TestInputs; - use tempfile::NamedTempFile; - /// Helper to get a standard circuit config for tests - fn test_circuit_config() -> CircuitConfig { - CircuitConfig::standard_recursion_zk_config() - } - - /// Helper to build a verifier from the circuit for testing. - /// In production, verifiers load pre-built circuit data from files. - fn build_test_verifier() -> plonky2::plonk::circuit_data::VerifierCircuitData { - use qp_wormhole_circuit::circuit::circuit_logic::WormholeCircuit; - WormholeCircuit::new(test_circuit_config()).build_verifier() - } - #[test] fn test_compute_output_amount() { // 0.1% fee (10 bps): output = input * 9990 / 10000 @@ -2388,228 +2370,9 @@ mod tests { assert_ne!(account1.account_id, account_different.account_id); } - /// Integration test: Generate a real ZK proof using test fixtures and verify it - #[test] - #[ignore] // This test is slow (~30s) - run with `cargo test -- --ignored` - fn test_full_proof_generation_and_verification() { - // Use test fixtures from qp-wormhole-test-helpers - let inputs = CircuitInputs::test_inputs_0(); - - // Verify the test inputs have correct fee configuration - assert_eq!(inputs.public.volume_fee_bps, VOLUME_FEE_BPS); - assert_eq!(inputs.public.asset_id, NATIVE_ASSET_ID); - - // Verify fee constraint is satisfied in test inputs - let input_amount = inputs.private.input_amount; - let output_amount = inputs.public.output_amount_1 + inputs.public.output_amount_2; - assert!( - (output_amount as u64) * 10000 <= - (input_amount as u64) * (10000 - VOLUME_FEE_BPS as u64), - "Test inputs violate fee constraint" - ); - - // Create prover and generate proof - let config = test_circuit_config(); - let prover = WormholeProver::new(config.clone()); - let prover_committed = prover.commit(&inputs).expect("Failed to commit inputs"); - let proof = prover_committed.prove().expect("Failed to generate proof"); - - // Parse and verify public inputs from proof - let parsed_public_inputs = - PublicCircuitInputs::try_from_proof(&proof).expect("Failed to parse public inputs"); - - assert_eq!(parsed_public_inputs.asset_id, inputs.public.asset_id); - assert_eq!(parsed_public_inputs.output_amount_1, inputs.public.output_amount_1); - assert_eq!(parsed_public_inputs.output_amount_2, inputs.public.output_amount_2); - assert_eq!(parsed_public_inputs.volume_fee_bps, inputs.public.volume_fee_bps); - assert_eq!(parsed_public_inputs.nullifier, inputs.public.nullifier); - assert_eq!(parsed_public_inputs.exit_account_1, inputs.public.exit_account_1); - assert_eq!(parsed_public_inputs.exit_account_2, inputs.public.exit_account_2); - assert_eq!(parsed_public_inputs.block_hash, inputs.public.block_hash); - assert_eq!(parsed_public_inputs.parent_hash, inputs.public.parent_hash); - assert_eq!(parsed_public_inputs.block_number, inputs.public.block_number); - - // Create verifier and verify proof - let verifier = build_test_verifier(); - verifier.verify(proof).expect("Proof verification failed"); - } - - /// Integration test: Generate proof, serialize/deserialize, then verify - #[test] - #[ignore] // This test is slow - run with `cargo test -- --ignored` - fn test_proof_serialization_roundtrip() { - let inputs = CircuitInputs::test_inputs_0(); - let config = test_circuit_config(); - - // Generate proof - let prover = WormholeProver::new(config.clone()); - let proof = prover.commit(&inputs).unwrap().prove().unwrap(); - - // Serialize to bytes - let proof_bytes = proof.to_bytes(); - - // Write to temp file and read back - let temp_file = NamedTempFile::new().unwrap(); - let path = temp_file.path().to_str().unwrap(); - write_proof_file(path, &proof_bytes).unwrap(); - let read_bytes = read_proof_file(path).unwrap(); - - assert_eq!(proof_bytes, read_bytes, "Proof bytes should match after file roundtrip"); - - // Deserialize and verify - let verifier = build_test_verifier(); - let deserialized_proof = plonky2::plonk::proof::ProofWithPublicInputs::< - qp_zk_circuits_common::circuit::F, - qp_zk_circuits_common::circuit::C, - { qp_zk_circuits_common::circuit::D }, - >::from_bytes(read_bytes, &verifier.common) - .expect("Failed to deserialize proof"); - - verifier - .verify(deserialized_proof) - .expect("Deserialized proof verification failed"); - } - - /// Integration test: Generate multiple proofs with different inputs - #[test] - #[ignore] // This test is slow - run with `cargo test -- --ignored` - fn test_multiple_proof_generation() { - let config = test_circuit_config(); - - // Generate proofs for both test input sets - let inputs_0 = CircuitInputs::test_inputs_0(); - let inputs_1 = CircuitInputs::test_inputs_1(); - - let prover_0 = WormholeProver::new(config.clone()); - let proof_0 = prover_0.commit(&inputs_0).unwrap().prove().unwrap(); - - let prover_1 = WormholeProver::new(config.clone()); - let proof_1 = prover_1.commit(&inputs_1).unwrap().prove().unwrap(); - - // Verify both proofs - let verifier = build_test_verifier(); - verifier.verify(proof_0.clone()).expect("Proof 0 verification failed"); - verifier.verify(proof_1.clone()).expect("Proof 1 verification failed"); - - // Verify public inputs are different (different nullifiers, etc.) - let public_0 = PublicCircuitInputs::try_from_proof(&proof_0).unwrap(); - let public_1 = PublicCircuitInputs::try_from_proof(&proof_1).unwrap(); - - assert_ne!(public_0.nullifier, public_1.nullifier, "Nullifiers should be different"); - assert_ne!(public_0.block_hash, public_1.block_hash, "Block hashes should be different"); - } - - /// Integration test: Aggregate proofs and verify aggregated proof - #[test] - #[ignore] // This test is slow (~60s) - run with `cargo test -- --ignored` - fn test_proof_aggregation() { - use qp_wormhole_aggregator::{ - aggregator::WormholeProofAggregator, circuits::tree::TreeAggregationConfig, - }; - - let config = test_circuit_config(); - let aggregation_config = TreeAggregationConfig::new(2, 1); // branching_factor=2, depth=1 - - // Generate a proof - let inputs = CircuitInputs::test_inputs_0(); - let prover = WormholeProver::new(config.clone()); - let proof = prover.commit(&inputs).unwrap().prove().unwrap(); - - // Create aggregator with explicit config - let mut aggregator = - WormholeProofAggregator::from_circuit_config(config, aggregation_config); - - // Add proof to aggregator - aggregator.push_proof(proof.clone()).expect("Failed to push proof"); - - // Aggregate - let aggregated_result = aggregator.aggregate().expect("Aggregation failed"); - - // Parse aggregated public inputs - let aggregated_public_inputs = AggregatedPublicCircuitInputs::try_from_felts( - aggregated_result.proof.public_inputs.as_slice(), - ) - .expect("Failed to parse aggregated public inputs"); - - // Verify aggregated proof structure - assert_eq!(aggregated_public_inputs.asset_id, NATIVE_ASSET_ID, "Asset ID should be native"); - assert_eq!( - aggregated_public_inputs.volume_fee_bps, VOLUME_FEE_BPS, - "Volume fee BPS should match" - ); - assert!( - !aggregated_public_inputs.nullifiers.is_empty(), - "Should have at least one nullifier" - ); - assert!( - !aggregated_public_inputs.account_data.is_empty(), - "Should have at least one account" - ); - - // Verify the aggregated proof locally - aggregated_result - .circuit_data - .verify(aggregated_result.proof) - .expect("Aggregated proof verification failed"); - } - - /// Integration test: Aggregate multiple proofs with different exit accounts - #[test] - #[ignore] // This test is very slow (~120s) - run with `cargo test -- --ignored` - fn test_proof_aggregation_multiple_accounts() { - use qp_wormhole_aggregator::{ - aggregator::WormholeProofAggregator, circuits::tree::TreeAggregationConfig, - }; - - let config = test_circuit_config(); - let aggregation_config = TreeAggregationConfig::new(2, 1); // branching_factor=2, depth=1 - - // Generate proofs with different inputs (different exit accounts) - let inputs_0 = CircuitInputs::test_inputs_0(); - let inputs_1 = CircuitInputs::test_inputs_1(); - - let prover_0 = WormholeProver::new(config.clone()); - let proof_0 = prover_0.commit(&inputs_0).unwrap().prove().unwrap(); - - let prover_1 = WormholeProver::new(config.clone()); - let proof_1 = prover_1.commit(&inputs_1).unwrap().prove().unwrap(); - - // Create aggregator with explicit config - let mut aggregator = - WormholeProofAggregator::from_circuit_config(config, aggregation_config); - - // Add both proofs - aggregator.push_proof(proof_0).expect("Failed to push proof 0"); - aggregator.push_proof(proof_1).expect("Failed to push proof 1"); - - // Aggregate - let aggregated_result = aggregator.aggregate().expect("Aggregation failed"); - - // Parse aggregated public inputs - let aggregated_public_inputs = AggregatedPublicCircuitInputs::try_from_felts( - aggregated_result.proof.public_inputs.as_slice(), - ) - .expect("Failed to parse aggregated public inputs"); - - // Verify we have 2 nullifiers (one per proof) - assert_eq!( - aggregated_public_inputs.nullifiers.len(), - 2, - "Should have 2 nullifiers for 2 proofs" - ); - - // Verify all nullifiers are unique - assert_ne!( - aggregated_public_inputs.nullifiers[0], aggregated_public_inputs.nullifiers[1], - "Nullifiers should be unique" - ); - - // Verify the aggregated proof - aggregated_result - .circuit_data - .verify(aggregated_result.proof) - .expect("Aggregated proof verification failed"); - } + // Note: Integration tests for proof generation, serialization, aggregation, and + // multi-account aggregation have been moved to qp-zk-circuits/wormhole/tests/ + // where the test-helpers crate (with TestInputs) is available as a workspace dep. /// Test that public inputs parsing matches expected structure #[test] From d06e94a0200a5b7e4a5a64179f80371463597d9c Mon Sep 17 00:00:00 2001 From: illuzen Date: Sun, 15 Feb 2026 23:37:21 +0800 Subject: [PATCH 17/26] point qp-dilithium-crypto to github --- Cargo.lock | 17 +++++++++-------- Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c0f46e6..aa40938 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,7 +1008,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -1420,7 +1420,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1611,7 +1611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3122,7 +3122,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3801,6 +3801,7 @@ dependencies = [ [[package]] name = "qp-dilithium-crypto" version = "0.2.0" +source = "git+https://github.com/Quantus-Network/chain?branch=testnet%2Fplanck#fc80f0359a0d3450151c8fe98fd5f92dab312d6a" dependencies = [ "log", "parity-scale-codec", @@ -4168,7 +4169,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -4460,7 +4461,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5970,7 +5971,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -6889,7 +6890,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index da6bd41..14897a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,4 +89,4 @@ tempfile = "3.8" serial_test = "3.1" [patch.crates-io] -qp-dilithium-crypto = { path = "../chain/primitives/dilithium-crypto" } +qp-dilithium-crypto = { git = "https://github.com/Quantus-Network/chain", branch = "testnet/planck" } From 9cd2fb60287f8f674b1ac9637c2e2707c6d3d853 Mon Sep 17 00:00:00 2001 From: illuzen Date: Sun, 15 Feb 2026 23:48:03 +0800 Subject: [PATCH 18/26] clippy again --- src/cli/wormhole.rs | 298 ++++++++++++++++++++++---------------------- 1 file changed, 149 insertions(+), 149 deletions(-) diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 8c2c45d..b60957a 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -2185,6 +2185,155 @@ fn run_multiround_dry_run( Ok(()) } +/// Parse and display the contents of a proof file for debugging +async fn parse_proof_file( + proof_file: String, + aggregated: bool, + verify: bool, +) -> crate::error::Result<()> { + use qp_wormhole_verifier::WormholeVerifier; + + log_print!("Parsing proof file: {}", proof_file); + + // Read proof bytes + let proof_bytes = read_proof_file(&proof_file) + .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to read proof: {}", e)))?; + + log_print!("Proof size: {} bytes", proof_bytes.len()); + + let bins_dir = Path::new("generated-bins"); + + if aggregated { + // Load aggregated verifier + let verifier = WormholeVerifier::new_from_files( + &bins_dir.join("aggregated_verifier.bin"), + &bins_dir.join("aggregated_common.bin"), + ) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) + })?; + + // Deserialize proof using verifier's types + let proof = qp_wormhole_verifier::ProofWithPublicInputs::< + qp_wormhole_verifier::F, + qp_wormhole_verifier::C, + { qp_wormhole_verifier::D }, + >::from_bytes(proof_bytes.clone(), &verifier.circuit_data.common) + .map_err(|e| { + crate::error::QuantusError::Generic(format!( + "Failed to deserialize aggregated proof: {:?}", + e + )) + })?; + + log_print!("\nPublic inputs count: {}", proof.public_inputs.len()); + log_verbose!("\nPublic inputs count: {}", proof.public_inputs.len()); + + // Try to parse as aggregated + match qp_wormhole_verifier::parse_aggregated_public_inputs(&proof) { + Ok(agg_inputs) => { + log_print!("\n=== Parsed Aggregated Public Inputs ==="); + log_print!("Asset ID: {}", agg_inputs.asset_id); + log_print!("Volume Fee BPS: {}", agg_inputs.volume_fee_bps); + log_print!( + "Block Hash: 0x{}", + hex::encode(agg_inputs.block_data.block_hash.as_ref()) + ); + log_print!("Block Number: {}", agg_inputs.block_data.block_number); + log_print!("\nAccount Data ({} accounts):", agg_inputs.account_data.len()); + for (i, acct) in agg_inputs.account_data.iter().enumerate() { + log_print!( + " [{}] amount={}, exit=0x{}", + i, + acct.summed_output_amount, + hex::encode(acct.exit_account.as_ref()) + ); + } + log_print!("\nNullifiers ({} nullifiers):", agg_inputs.nullifiers.len()); + for (i, nullifier) in agg_inputs.nullifiers.iter().enumerate() { + log_print!(" [{}] 0x{}", i, hex::encode(nullifier.as_ref())); + } + }, + Err(e) => { + log_print!("Failed to parse as aggregated inputs: {}", e); + }, + } + + // Verify if requested + if verify { + log_print!("\n=== Verifying Proof ==="); + match verifier.verify(proof) { + Ok(()) => { + log_success!("Proof verification PASSED"); + }, + Err(e) => { + log_error!("Proof verification FAILED: {}", e); + return Err(crate::error::QuantusError::Generic(format!( + "Proof verification failed: {}", + e + ))); + }, + } + } + } else { + // Load leaf verifier + let verifier = WormholeVerifier::new_from_files( + &bins_dir.join("verifier.bin"), + &bins_dir.join("common.bin"), + ) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) + })?; + + // Deserialize proof using verifier's types + let proof = qp_wormhole_verifier::ProofWithPublicInputs::< + qp_wormhole_verifier::F, + qp_wormhole_verifier::C, + { qp_wormhole_verifier::D }, + >::from_bytes(proof_bytes, &verifier.circuit_data.common) + .map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to deserialize proof: {:?}", e)) + })?; + + log_print!("\nPublic inputs count: {}", proof.public_inputs.len()); + + let pi = qp_wormhole_verifier::parse_public_inputs(&proof).map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to parse public inputs: {}", e)) + })?; + + log_print!("\n=== Parsed Leaf Public Inputs ==="); + log_print!("Asset ID: {}", pi.asset_id); + log_print!("Output Amount 1: {}", pi.output_amount_1); + log_print!("Output Amount 2: {}", pi.output_amount_2); + log_print!("Volume Fee BPS: {}", pi.volume_fee_bps); + log_print!("Nullifier: 0x{}", hex::encode(pi.nullifier.as_ref())); + log_print!("Exit Account 1: 0x{}", hex::encode(pi.exit_account_1.as_ref())); + log_print!("Exit Account 2: 0x{}", hex::encode(pi.exit_account_2.as_ref())); + log_print!("Block Hash: 0x{}", hex::encode(pi.block_hash.as_ref())); + log_print!("Parent Hash: 0x{}", hex::encode(pi.parent_hash.as_ref())); + log_print!("Block Number: {}", pi.block_number); + + // Verify if requested + if verify { + log_print!("\n=== Verifying Proof ==="); + match verifier.verify(proof) { + Ok(()) => { + log_success!("Proof verification PASSED"); + }, + Err(e) => { + log_error!("Proof verification FAILED: {}", e); + return Err(crate::error::QuantusError::Generic(format!( + "Proof verification failed: {}", + e + ))); + }, + } + } + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -2429,152 +2578,3 @@ mod tests { assert_eq!(VOLUME_FEE_BPS, 10); } } - -/// Parse and display the contents of a proof file for debugging -async fn parse_proof_file( - proof_file: String, - aggregated: bool, - verify: bool, -) -> crate::error::Result<()> { - use qp_wormhole_verifier::WormholeVerifier; - - log_print!("Parsing proof file: {}", proof_file); - - // Read proof bytes - let proof_bytes = read_proof_file(&proof_file) - .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to read proof: {}", e)))?; - - log_print!("Proof size: {} bytes", proof_bytes.len()); - - let bins_dir = Path::new("generated-bins"); - - if aggregated { - // Load aggregated verifier - let verifier = WormholeVerifier::new_from_files( - &bins_dir.join("aggregated_verifier.bin"), - &bins_dir.join("aggregated_common.bin"), - ) - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) - })?; - - // Deserialize proof using verifier's types - let proof = qp_wormhole_verifier::ProofWithPublicInputs::< - qp_wormhole_verifier::F, - qp_wormhole_verifier::C, - { qp_wormhole_verifier::D }, - >::from_bytes(proof_bytes.clone(), &verifier.circuit_data.common) - .map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to deserialize aggregated proof: {:?}", - e - )) - })?; - - log_print!("\nPublic inputs count: {}", proof.public_inputs.len()); - log_verbose!("\nPublic inputs count: {}", proof.public_inputs.len()); - - // Try to parse as aggregated - match qp_wormhole_verifier::parse_aggregated_public_inputs(&proof) { - Ok(agg_inputs) => { - log_print!("\n=== Parsed Aggregated Public Inputs ==="); - log_print!("Asset ID: {}", agg_inputs.asset_id); - log_print!("Volume Fee BPS: {}", agg_inputs.volume_fee_bps); - log_print!( - "Block Hash: 0x{}", - hex::encode(agg_inputs.block_data.block_hash.as_ref()) - ); - log_print!("Block Number: {}", agg_inputs.block_data.block_number); - log_print!("\nAccount Data ({} accounts):", agg_inputs.account_data.len()); - for (i, acct) in agg_inputs.account_data.iter().enumerate() { - log_print!( - " [{}] amount={}, exit=0x{}", - i, - acct.summed_output_amount, - hex::encode(acct.exit_account.as_ref()) - ); - } - log_print!("\nNullifiers ({} nullifiers):", agg_inputs.nullifiers.len()); - for (i, nullifier) in agg_inputs.nullifiers.iter().enumerate() { - log_print!(" [{}] 0x{}", i, hex::encode(nullifier.as_ref())); - } - }, - Err(e) => { - log_print!("Failed to parse as aggregated inputs: {}", e); - }, - } - - // Verify if requested - if verify { - log_print!("\n=== Verifying Proof ==="); - match verifier.verify(proof) { - Ok(()) => { - log_success!("Proof verification PASSED"); - }, - Err(e) => { - log_error!("Proof verification FAILED: {}", e); - return Err(crate::error::QuantusError::Generic(format!( - "Proof verification failed: {}", - e - ))); - }, - } - } - } else { - // Load leaf verifier - let verifier = WormholeVerifier::new_from_files( - &bins_dir.join("verifier.bin"), - &bins_dir.join("common.bin"), - ) - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to load verifier: {}", e)) - })?; - - // Deserialize proof using verifier's types - let proof = qp_wormhole_verifier::ProofWithPublicInputs::< - qp_wormhole_verifier::F, - qp_wormhole_verifier::C, - { qp_wormhole_verifier::D }, - >::from_bytes(proof_bytes, &verifier.circuit_data.common) - .map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to deserialize proof: {:?}", e)) - })?; - - log_print!("\nPublic inputs count: {}", proof.public_inputs.len()); - - let pi = qp_wormhole_verifier::parse_public_inputs(&proof).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to parse public inputs: {}", e)) - })?; - - log_print!("\n=== Parsed Leaf Public Inputs ==="); - log_print!("Asset ID: {}", pi.asset_id); - log_print!("Output Amount 1: {}", pi.output_amount_1); - log_print!("Output Amount 2: {}", pi.output_amount_2); - log_print!("Volume Fee BPS: {}", pi.volume_fee_bps); - log_print!("Nullifier: 0x{}", hex::encode(pi.nullifier.as_ref())); - log_print!("Exit Account 1: 0x{}", hex::encode(pi.exit_account_1.as_ref())); - log_print!("Exit Account 2: 0x{}", hex::encode(pi.exit_account_2.as_ref())); - log_print!("Block Hash: 0x{}", hex::encode(pi.block_hash.as_ref())); - log_print!("Parent Hash: 0x{}", hex::encode(pi.parent_hash.as_ref())); - log_print!("Block Number: {}", pi.block_number); - - // Verify if requested - if verify { - log_print!("\n=== Verifying Proof ==="); - match verifier.verify(proof) { - Ok(()) => { - log_success!("Proof verification PASSED"); - }, - Err(e) => { - log_error!("Proof verification FAILED: {}", e); - return Err(crate::error::QuantusError::Generic(format!( - "Proof verification failed: {}", - e - ))); - }, - } - } - } - - Ok(()) -} From a30b57911f0bf395d5a5a301734e92d9ca532093 Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Mon, 16 Feb 2026 08:52:07 +0800 Subject: [PATCH 19/26] feat: Metadata updated --- src/chain/quantus_subxt.rs | 9886 ++++++++++++++++++------------------ src/quantus_metadata.scale | Bin 167504 -> 169195 bytes 2 files changed, 4908 insertions(+), 4978 deletions(-) diff --git a/src/chain/quantus_subxt.rs b/src/chain/quantus_subxt.rs index 05e2ec8..0651a80 100644 --- a/src/chain/quantus_subxt.rs +++ b/src/chain/quantus_subxt.rs @@ -6,7 +6,7 @@ pub mod api { mod root_mod { pub use super::*; } - pub static PALLETS: [&str; 23usize] = [ + pub static PALLETS: [&str; 22usize] = [ "System", "Timestamp", "Balances", @@ -14,7 +14,6 @@ pub mod api { "Sudo", "QPoW", "MiningRewards", - "Vesting", "Preimage", "Scheduler", "Utility", @@ -23,12 +22,12 @@ pub mod api { "ConvictionVoting", "TechCollective", "TechReferenda", - "MerkleAirdrop", "TreasuryPallet", "Origins", "Recovery", "Assets", "AssetsHolder", + "Multisig", "Wormhole", ]; pub static RUNTIME_APIS: [&str; 11usize] = [ @@ -1471,9 +1470,9 @@ pub mod api { "query_call_info", types::QueryCallInfo { call, len }, [ - 144u8, 69u8, 76u8, 20u8, 225u8, 168u8, 95u8, 163u8, 136u8, 202u8, 72u8, - 27u8, 234u8, 2u8, 87u8, 1u8, 106u8, 223u8, 192u8, 30u8, 20u8, 233u8, - 167u8, 128u8, 112u8, 225u8, 153u8, 125u8, 248u8, 228u8, 53u8, 167u8, + 204u8, 150u8, 141u8, 3u8, 172u8, 39u8, 127u8, 54u8, 249u8, 96u8, 163u8, + 158u8, 93u8, 236u8, 159u8, 71u8, 49u8, 22u8, 104u8, 202u8, 3u8, 96u8, + 247u8, 91u8, 244u8, 94u8, 201u8, 162u8, 142u8, 28u8, 197u8, 142u8, ], ) } @@ -1491,10 +1490,9 @@ pub mod api { "query_call_fee_details", types::QueryCallFeeDetails { call, len }, [ - 86u8, 238u8, 23u8, 213u8, 191u8, 145u8, 151u8, 110u8, 183u8, 238u8, - 148u8, 145u8, 134u8, 41u8, 240u8, 193u8, 187u8, 232u8, 19u8, 217u8, - 179u8, 188u8, 8u8, 191u8, 23u8, 18u8, 155u8, 52u8, 12u8, 169u8, 221u8, - 101u8, + 188u8, 8u8, 21u8, 155u8, 112u8, 74u8, 100u8, 5u8, 115u8, 144u8, 213u8, + 217u8, 106u8, 97u8, 48u8, 45u8, 93u8, 58u8, 101u8, 97u8, 226u8, 204u8, + 167u8, 167u8, 138u8, 151u8, 24u8, 106u8, 149u8, 11u8, 55u8, 170u8, ], ) } @@ -1834,9 +1832,6 @@ pub mod api { pub fn mining_rewards(&self) -> mining_rewards::constants::ConstantsApi { mining_rewards::constants::ConstantsApi } - pub fn vesting(&self) -> vesting::constants::ConstantsApi { - vesting::constants::ConstantsApi - } pub fn scheduler(&self) -> scheduler::constants::ConstantsApi { scheduler::constants::ConstantsApi } @@ -1855,9 +1850,6 @@ pub mod api { pub fn tech_referenda(&self) -> tech_referenda::constants::ConstantsApi { tech_referenda::constants::ConstantsApi } - pub fn merkle_airdrop(&self) -> merkle_airdrop::constants::ConstantsApi { - merkle_airdrop::constants::ConstantsApi - } pub fn treasury_pallet(&self) -> treasury_pallet::constants::ConstantsApi { treasury_pallet::constants::ConstantsApi } @@ -1867,6 +1859,9 @@ pub mod api { pub fn assets(&self) -> assets::constants::ConstantsApi { assets::constants::ConstantsApi } + pub fn multisig(&self) -> multisig::constants::ConstantsApi { + multisig::constants::ConstantsApi + } pub fn wormhole(&self) -> wormhole::constants::ConstantsApi { wormhole::constants::ConstantsApi } @@ -1894,9 +1889,6 @@ pub mod api { pub fn mining_rewards(&self) -> mining_rewards::storage::StorageApi { mining_rewards::storage::StorageApi } - pub fn vesting(&self) -> vesting::storage::StorageApi { - vesting::storage::StorageApi - } pub fn preimage(&self) -> preimage::storage::StorageApi { preimage::storage::StorageApi } @@ -1918,9 +1910,6 @@ pub mod api { pub fn tech_referenda(&self) -> tech_referenda::storage::StorageApi { tech_referenda::storage::StorageApi } - pub fn merkle_airdrop(&self) -> merkle_airdrop::storage::StorageApi { - merkle_airdrop::storage::StorageApi - } pub fn treasury_pallet(&self) -> treasury_pallet::storage::StorageApi { treasury_pallet::storage::StorageApi } @@ -1933,6 +1922,9 @@ pub mod api { pub fn assets_holder(&self) -> assets_holder::storage::StorageApi { assets_holder::storage::StorageApi } + pub fn multisig(&self) -> multisig::storage::StorageApi { + multisig::storage::StorageApi + } pub fn wormhole(&self) -> wormhole::storage::StorageApi { wormhole::storage::StorageApi } @@ -1951,9 +1943,6 @@ pub mod api { pub fn sudo(&self) -> sudo::calls::TransactionApi { sudo::calls::TransactionApi } - pub fn vesting(&self) -> vesting::calls::TransactionApi { - vesting::calls::TransactionApi - } pub fn preimage(&self) -> preimage::calls::TransactionApi { preimage::calls::TransactionApi } @@ -1978,9 +1967,6 @@ pub mod api { pub fn tech_referenda(&self) -> tech_referenda::calls::TransactionApi { tech_referenda::calls::TransactionApi } - pub fn merkle_airdrop(&self) -> merkle_airdrop::calls::TransactionApi { - merkle_airdrop::calls::TransactionApi - } pub fn treasury_pallet(&self) -> treasury_pallet::calls::TransactionApi { treasury_pallet::calls::TransactionApi } @@ -1990,6 +1976,9 @@ pub mod api { pub fn assets(&self) -> assets::calls::TransactionApi { assets::calls::TransactionApi } + pub fn multisig(&self) -> multisig::calls::TransactionApi { + multisig::calls::TransactionApi + } pub fn wormhole(&self) -> wormhole::calls::TransactionApi { wormhole::calls::TransactionApi } @@ -2005,9 +1994,9 @@ pub mod api { .hash(); runtime_metadata_hash == [ - 188u8, 39u8, 127u8, 207u8, 32u8, 174u8, 40u8, 37u8, 8u8, 103u8, 134u8, 90u8, 25u8, - 13u8, 113u8, 231u8, 42u8, 35u8, 1u8, 219u8, 62u8, 142u8, 175u8, 90u8, 219u8, 204u8, - 82u8, 53u8, 187u8, 156u8, 226u8, 105u8, + 60u8, 255u8, 4u8, 208u8, 41u8, 252u8, 232u8, 254u8, 146u8, 6u8, 174u8, 75u8, 170u8, + 225u8, 3u8, 217u8, 68u8, 231u8, 231u8, 227u8, 166u8, 46u8, 206u8, 236u8, 155u8, + 201u8, 2u8, 240u8, 72u8, 62u8, 125u8, 106u8, ] } pub mod system { @@ -3106,10 +3095,9 @@ pub mod api { "Events", (), [ - 233u8, 203u8, 207u8, 158u8, 57u8, 161u8, 88u8, 160u8, 148u8, 0u8, - 176u8, 254u8, 251u8, 206u8, 46u8, 94u8, 178u8, 136u8, 154u8, 109u8, - 197u8, 147u8, 125u8, 17u8, 120u8, 246u8, 69u8, 50u8, 48u8, 172u8, 81u8, - 34u8, + 137u8, 200u8, 171u8, 24u8, 189u8, 55u8, 241u8, 103u8, 215u8, 54u8, + 98u8, 177u8, 217u8, 184u8, 55u8, 205u8, 187u8, 36u8, 71u8, 136u8, 71u8, + 63u8, 1u8, 7u8, 221u8, 213u8, 113u8, 189u8, 226u8, 251u8, 216u8, 172u8, ], ) } @@ -5389,10 +5377,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 168u8, 100u8, 48u8, 116u8, 163u8, 192u8, 242u8, 52u8, 119u8, 87u8, - 194u8, 233u8, 96u8, 99u8, 148u8, 199u8, 189u8, 152u8, 42u8, 69u8, - 195u8, 93u8, 2u8, 53u8, 139u8, 85u8, 19u8, 63u8, 251u8, 30u8, 244u8, - 30u8, + 139u8, 70u8, 66u8, 133u8, 103u8, 122u8, 116u8, 79u8, 33u8, 114u8, + 121u8, 140u8, 45u8, 159u8, 190u8, 20u8, 82u8, 18u8, 149u8, 237u8, + 153u8, 207u8, 254u8, 49u8, 229u8, 147u8, 158u8, 47u8, 98u8, 221u8, + 64u8, 208u8, ], ) } @@ -5415,10 +5403,9 @@ pub mod api { weight, }, [ - 181u8, 252u8, 48u8, 252u8, 226u8, 4u8, 157u8, 205u8, 114u8, 223u8, - 86u8, 149u8, 228u8, 170u8, 164u8, 255u8, 152u8, 191u8, 239u8, 205u8, - 149u8, 126u8, 209u8, 188u8, 197u8, 250u8, 24u8, 208u8, 212u8, 168u8, - 66u8, 131u8, + 161u8, 255u8, 101u8, 97u8, 2u8, 224u8, 1u8, 98u8, 65u8, 47u8, 40u8, + 73u8, 58u8, 241u8, 87u8, 27u8, 49u8, 27u8, 58u8, 156u8, 63u8, 175u8, + 215u8, 152u8, 16u8, 46u8, 118u8, 155u8, 93u8, 41u8, 165u8, 173u8, ], ) } @@ -5456,10 +5443,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 158u8, 186u8, 229u8, 16u8, 76u8, 224u8, 81u8, 198u8, 111u8, 234u8, - 112u8, 64u8, 248u8, 191u8, 138u8, 69u8, 111u8, 215u8, 204u8, 69u8, - 43u8, 60u8, 173u8, 141u8, 200u8, 113u8, 143u8, 75u8, 33u8, 84u8, 108u8, - 149u8, + 29u8, 143u8, 178u8, 190u8, 95u8, 145u8, 17u8, 240u8, 94u8, 218u8, 89u8, + 233u8, 194u8, 39u8, 196u8, 247u8, 210u8, 165u8, 71u8, 62u8, 164u8, + 175u8, 42u8, 179u8, 137u8, 187u8, 177u8, 10u8, 248u8, 157u8, 91u8, + 93u8, ], ) } @@ -5987,15 +5974,31 @@ pub mod api { use super::runtime_types; pub struct ConstantsApi; impl ConstantsApi { - #[doc = " The base block reward given to miners"] - pub fn miner_block_reward( + #[doc = " The maximum total supply of tokens"] + pub fn max_supply( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "MiningRewards", + "MaxSupply", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) + } + #[doc = " The divisor used to calculate block rewards from remaining supply"] + pub fn emission_divisor( &self, ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< ::core::primitive::u128, > { ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( "MiningRewards", - "MinerBlockReward", + "EmissionDivisor", [ 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, @@ -6003,15 +6006,31 @@ pub mod api { ], ) } - #[doc = " The base block reward given to treasury"] - pub fn treasury_block_reward( + #[doc = " The portion of rewards that goes to treasury"] + pub fn treasury_portion( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + runtime_types::sp_arithmetic::per_things::Permill, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "MiningRewards", + "TreasuryPortion", + [ + 65u8, 93u8, 120u8, 165u8, 204u8, 81u8, 159u8, 163u8, 93u8, 135u8, + 114u8, 121u8, 147u8, 35u8, 215u8, 213u8, 4u8, 223u8, 83u8, 37u8, 225u8, + 200u8, 189u8, 156u8, 140u8, 36u8, 58u8, 46u8, 42u8, 232u8, 155u8, 0u8, + ], + ) + } + #[doc = " The base unit for token amounts (e.g., 1e12 for 12 decimals)"] + pub fn unit( &self, ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< ::core::primitive::u128, > { ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( "MiningRewards", - "TreasuryBlockReward", + "Unit", [ 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, @@ -6055,12 +6074,12 @@ pub mod api { } } } - pub mod vesting { + pub mod preimage { use super::{root_mod, runtime_types}; - #[doc = "Error for the vesting pallet."] - pub type Error = runtime_types::pallet_vesting::pallet::Error; + #[doc = "The `Error` enum of this pallet."] + pub type Error = runtime_types::pallet_preimage::pallet::Error; #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_vesting::pallet::Call; + pub type Call = runtime_types::pallet_preimage::pallet::Call; pub mod calls { use super::{root_mod, runtime_types}; type DispatchError = runtime_types::sp_runtime::DispatchError; @@ -6077,55 +6096,21 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Unlock any vested funds of the sender account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_ and the sender must have funds still"] - #[doc = "locked under this pallet."] - #[doc = ""] - #[doc = "Emits either `VestingCompleted` or `VestingUpdated`."] - #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - pub struct Vest; - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Vest { - const PALLET: &'static str = "Vesting"; - const CALL: &'static str = "vest"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Unlock any vested funds of a `target` account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - #[doc = ""] - #[doc = "- `target`: The account whose vested funds should be unlocked. Must have funds still"] - #[doc = "locked under this pallet."] - #[doc = ""] - #[doc = "Emits either `VestingCompleted` or `VestingUpdated`."] + #[doc = "Register a preimage on-chain."] #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - pub struct VestOther { - pub target: vest_other::Target, + #[doc = "If the preimage was previously requested, no fees or deposits are taken for providing"] + #[doc = "the preimage. Otherwise, a deposit is taken proportional to the size of the preimage."] + pub struct NotePreimage { + pub bytes: note_preimage::Bytes, } - pub mod vest_other { + pub mod note_preimage { use super::runtime_types; - pub type Target = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; + pub type Bytes = + ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for VestOther { - const PALLET: &'static str = "Vesting"; - const CALL: &'static str = "vest_other"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for NotePreimage { + const PALLET: &'static str = "Preimage"; + const CALL: &'static str = "note_preimage"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6138,37 +6123,22 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Create a vested transfer."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - #[doc = ""] - #[doc = "- `target`: The account receiving the vested funds."] - #[doc = "- `schedule`: The vesting schedule attached to the transfer."] - #[doc = ""] - #[doc = "Emits `VestingCreated`."] + #[doc = "Clear an unrequested preimage from the runtime storage."] #[doc = ""] - #[doc = "NOTE: This will unlock all schedules through the current block."] + #[doc = "If `len` is provided, then it will be a much cheaper operation."] #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - pub struct VestedTransfer { - pub target: vested_transfer::Target, - pub schedule: vested_transfer::Schedule, + #[doc = "- `hash`: The hash of the preimage to be removed from the store."] + #[doc = "- `len`: The length of the preimage of `hash`."] + pub struct UnnotePreimage { + pub hash: unnote_preimage::Hash, } - pub mod vested_transfer { + pub mod unnote_preimage { use super::runtime_types; - pub type Target = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - pub type Schedule = runtime_types::pallet_vesting::vesting_info::VestingInfo< - ::core::primitive::u128, - ::core::primitive::u32, - >; + pub type Hash = ::subxt::ext::subxt_core::utils::H256; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for VestedTransfer { - const PALLET: &'static str = "Vesting"; - const CALL: &'static str = "vested_transfer"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for UnnotePreimage { + const PALLET: &'static str = "Preimage"; + const CALL: &'static str = "unnote_preimage"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6181,43 +6151,20 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Force a vested transfer."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Root_."] - #[doc = ""] - #[doc = "- `source`: The account whose funds should be transferred."] - #[doc = "- `target`: The account that should be transferred the vested funds."] - #[doc = "- `schedule`: The vesting schedule attached to the transfer."] - #[doc = ""] - #[doc = "Emits `VestingCreated`."] - #[doc = ""] - #[doc = "NOTE: This will unlock all schedules through the current block."] + #[doc = "Request a preimage be uploaded to the chain without paying any fees or deposits."] #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - pub struct ForceVestedTransfer { - pub source: force_vested_transfer::Source, - pub target: force_vested_transfer::Target, - pub schedule: force_vested_transfer::Schedule, + #[doc = "If the preimage requests has already been provided on-chain, we unreserve any deposit"] + #[doc = "a user may have paid, and take the control of the preimage out of their hands."] + pub struct RequestPreimage { + pub hash: request_preimage::Hash, } - pub mod force_vested_transfer { + pub mod request_preimage { use super::runtime_types; - pub type Source = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - pub type Target = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - pub type Schedule = runtime_types::pallet_vesting::vesting_info::VestingInfo< - ::core::primitive::u128, - ::core::primitive::u32, - >; + pub type Hash = ::subxt::ext::subxt_core::utils::H256; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ForceVestedTransfer { - const PALLET: &'static str = "Vesting"; - const CALL: &'static str = "force_vested_transfer"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for RequestPreimage { + const PALLET: &'static str = "Preimage"; + const CALL: &'static str = "request_preimage"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6230,39 +6177,19 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Merge two vesting schedules together, creating a new vesting schedule that unlocks over"] - #[doc = "the highest possible start and end blocks. If both schedules have already started the"] - #[doc = "current block will be used as the schedule start; with the caveat that if one schedule"] - #[doc = "is finished by the current block, the other will be treated as the new merged schedule,"] - #[doc = "unmodified."] - #[doc = ""] - #[doc = "NOTE: If `schedule1_index == schedule2_index` this is a no-op."] - #[doc = "NOTE: This will unlock all schedules through the current block prior to merging."] - #[doc = "NOTE: If both schedules have ended by the current block, no new schedule will be created"] - #[doc = "and both will be removed."] - #[doc = ""] - #[doc = "Merged schedule attributes:"] - #[doc = "- `starting_block`: `MAX(schedule1.starting_block, scheduled2.starting_block,"] - #[doc = " current_block)`."] - #[doc = "- `ending_block`: `MAX(schedule1.ending_block, schedule2.ending_block)`."] - #[doc = "- `locked`: `schedule1.locked_at(current_block) + schedule2.locked_at(current_block)`."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = "Clear a previously made request for a preimage."] #[doc = ""] - #[doc = "- `schedule1_index`: index of the first schedule to merge."] - #[doc = "- `schedule2_index`: index of the second schedule to merge."] - pub struct MergeSchedules { - pub schedule1_index: merge_schedules::Schedule1Index, - pub schedule2_index: merge_schedules::Schedule2Index, + #[doc = "NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`."] + pub struct UnrequestPreimage { + pub hash: unrequest_preimage::Hash, } - pub mod merge_schedules { + pub mod unrequest_preimage { use super::runtime_types; - pub type Schedule1Index = ::core::primitive::u32; - pub type Schedule2Index = ::core::primitive::u32; + pub type Hash = ::subxt::ext::subxt_core::utils::H256; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for MergeSchedules { - const PALLET: &'static str = "Vesting"; - const CALL: &'static str = "merge_schedules"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for UnrequestPreimage { + const PALLET: &'static str = "Preimage"; + const CALL: &'static str = "unrequest_preimage"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6275,210 +6202,131 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Force remove a vesting schedule"] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Root_."] + #[doc = "Ensure that the bulk of pre-images is upgraded."] #[doc = ""] - #[doc = "- `target`: An account that has a vesting schedule"] - #[doc = "- `schedule_index`: The vesting schedule index that should be removed"] - pub struct ForceRemoveVestingSchedule { - pub target: force_remove_vesting_schedule::Target, - pub schedule_index: force_remove_vesting_schedule::ScheduleIndex, + #[doc = "The caller pays no fee if at least 90% of pre-images were successfully updated."] + pub struct EnsureUpdated { + pub hashes: ensure_updated::Hashes, } - pub mod force_remove_vesting_schedule { + pub mod ensure_updated { use super::runtime_types; - pub type Target = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), + pub type Hashes = ::subxt::ext::subxt_core::alloc::vec::Vec< + ::subxt::ext::subxt_core::utils::H256, >; - pub type ScheduleIndex = ::core::primitive::u32; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ForceRemoveVestingSchedule { - const PALLET: &'static str = "Vesting"; - const CALL: &'static str = "force_remove_vesting_schedule"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for EnsureUpdated { + const PALLET: &'static str = "Preimage"; + const CALL: &'static str = "ensure_updated"; } } pub struct TransactionApi; impl TransactionApi { - #[doc = "Unlock any vested funds of the sender account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_ and the sender must have funds still"] - #[doc = "locked under this pallet."] - #[doc = ""] - #[doc = "Emits either `VestingCompleted` or `VestingUpdated`."] - #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - pub fn vest( - &self, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Vesting", - "vest", - types::Vest {}, - [ - 149u8, 89u8, 178u8, 148u8, 127u8, 127u8, 155u8, 60u8, 114u8, 126u8, - 204u8, 123u8, 166u8, 70u8, 104u8, 208u8, 186u8, 69u8, 139u8, 181u8, - 151u8, 154u8, 235u8, 161u8, 191u8, 35u8, 111u8, 60u8, 21u8, 165u8, - 44u8, 122u8, - ], - ) - } - #[doc = "Unlock any vested funds of a `target` account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - #[doc = ""] - #[doc = "- `target`: The account whose vested funds should be unlocked. Must have funds still"] - #[doc = "locked under this pallet."] - #[doc = ""] - #[doc = "Emits either `VestingCompleted` or `VestingUpdated`."] + #[doc = "Register a preimage on-chain."] #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - pub fn vest_other( + #[doc = "If the preimage was previously requested, no fees or deposits are taken for providing"] + #[doc = "the preimage. Otherwise, a deposit is taken proportional to the size of the preimage."] + pub fn note_preimage( &self, - target: types::vest_other::Target, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + bytes: types::note_preimage::Bytes, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Vesting", - "vest_other", - types::VestOther { target }, + "Preimage", + "note_preimage", + types::NotePreimage { bytes }, [ - 238u8, 92u8, 25u8, 149u8, 27u8, 211u8, 196u8, 31u8, 211u8, 28u8, 241u8, - 30u8, 128u8, 35u8, 0u8, 227u8, 202u8, 215u8, 186u8, 69u8, 216u8, 110u8, - 199u8, 120u8, 134u8, 141u8, 176u8, 224u8, 234u8, 42u8, 152u8, 128u8, + 121u8, 88u8, 18u8, 92u8, 176u8, 15u8, 192u8, 198u8, 146u8, 198u8, 38u8, + 242u8, 213u8, 83u8, 7u8, 230u8, 14u8, 110u8, 235u8, 32u8, 215u8, 26u8, + 192u8, 217u8, 113u8, 224u8, 206u8, 96u8, 177u8, 198u8, 246u8, 33u8, ], ) } - #[doc = "Create a vested transfer."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - #[doc = ""] - #[doc = "- `target`: The account receiving the vested funds."] - #[doc = "- `schedule`: The vesting schedule attached to the transfer."] - #[doc = ""] - #[doc = "Emits `VestingCreated`."] + #[doc = "Clear an unrequested preimage from the runtime storage."] #[doc = ""] - #[doc = "NOTE: This will unlock all schedules through the current block."] + #[doc = "If `len` is provided, then it will be a much cheaper operation."] #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - pub fn vested_transfer( + #[doc = "- `hash`: The hash of the preimage to be removed from the store."] + #[doc = "- `len`: The length of the preimage of `hash`."] + pub fn unnote_preimage( &self, - target: types::vested_transfer::Target, - schedule: types::vested_transfer::Schedule, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + hash: types::unnote_preimage::Hash, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Vesting", - "vested_transfer", - types::VestedTransfer { target, schedule }, + "Preimage", + "unnote_preimage", + types::UnnotePreimage { hash }, [ - 198u8, 133u8, 254u8, 5u8, 22u8, 170u8, 205u8, 79u8, 218u8, 30u8, 81u8, - 207u8, 227u8, 121u8, 132u8, 14u8, 217u8, 43u8, 66u8, 206u8, 15u8, 80u8, - 173u8, 208u8, 128u8, 72u8, 223u8, 175u8, 93u8, 69u8, 128u8, 88u8, + 188u8, 116u8, 222u8, 22u8, 127u8, 215u8, 2u8, 133u8, 96u8, 202u8, + 190u8, 123u8, 203u8, 43u8, 200u8, 161u8, 226u8, 24u8, 49u8, 36u8, + 221u8, 160u8, 130u8, 119u8, 30u8, 138u8, 144u8, 85u8, 5u8, 164u8, + 252u8, 222u8, ], ) } - #[doc = "Force a vested transfer."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Root_."] - #[doc = ""] - #[doc = "- `source`: The account whose funds should be transferred."] - #[doc = "- `target`: The account that should be transferred the vested funds."] - #[doc = "- `schedule`: The vesting schedule attached to the transfer."] - #[doc = ""] - #[doc = "Emits `VestingCreated`."] - #[doc = ""] - #[doc = "NOTE: This will unlock all schedules through the current block."] + #[doc = "Request a preimage be uploaded to the chain without paying any fees or deposits."] #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - pub fn force_vested_transfer( + #[doc = "If the preimage requests has already been provided on-chain, we unreserve any deposit"] + #[doc = "a user may have paid, and take the control of the preimage out of their hands."] + pub fn request_preimage( &self, - source: types::force_vested_transfer::Source, - target: types::force_vested_transfer::Target, - schedule: types::force_vested_transfer::Schedule, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + hash: types::request_preimage::Hash, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Vesting", - "force_vested_transfer", - types::ForceVestedTransfer { source, target, schedule }, + "Preimage", + "request_preimage", + types::RequestPreimage { hash }, [ - 112u8, 17u8, 176u8, 133u8, 169u8, 192u8, 155u8, 217u8, 153u8, 36u8, - 230u8, 45u8, 9u8, 192u8, 2u8, 201u8, 165u8, 60u8, 206u8, 226u8, 95u8, - 86u8, 239u8, 196u8, 109u8, 62u8, 224u8, 237u8, 88u8, 74u8, 209u8, - 251u8, + 87u8, 0u8, 204u8, 111u8, 43u8, 115u8, 64u8, 209u8, 133u8, 13u8, 83u8, + 45u8, 164u8, 166u8, 233u8, 105u8, 242u8, 238u8, 235u8, 208u8, 113u8, + 134u8, 93u8, 242u8, 86u8, 32u8, 7u8, 152u8, 107u8, 208u8, 79u8, 59u8, ], ) } - #[doc = "Merge two vesting schedules together, creating a new vesting schedule that unlocks over"] - #[doc = "the highest possible start and end blocks. If both schedules have already started the"] - #[doc = "current block will be used as the schedule start; with the caveat that if one schedule"] - #[doc = "is finished by the current block, the other will be treated as the new merged schedule,"] - #[doc = "unmodified."] - #[doc = ""] - #[doc = "NOTE: If `schedule1_index == schedule2_index` this is a no-op."] - #[doc = "NOTE: This will unlock all schedules through the current block prior to merging."] - #[doc = "NOTE: If both schedules have ended by the current block, no new schedule will be created"] - #[doc = "and both will be removed."] - #[doc = ""] - #[doc = "Merged schedule attributes:"] - #[doc = "- `starting_block`: `MAX(schedule1.starting_block, scheduled2.starting_block,"] - #[doc = " current_block)`."] - #[doc = "- `ending_block`: `MAX(schedule1.ending_block, schedule2.ending_block)`."] - #[doc = "- `locked`: `schedule1.locked_at(current_block) + schedule2.locked_at(current_block)`."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = "Clear a previously made request for a preimage."] #[doc = ""] - #[doc = "- `schedule1_index`: index of the first schedule to merge."] - #[doc = "- `schedule2_index`: index of the second schedule to merge."] - pub fn merge_schedules( + #[doc = "NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`."] + pub fn unrequest_preimage( &self, - schedule1_index: types::merge_schedules::Schedule1Index, - schedule2_index: types::merge_schedules::Schedule2Index, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + hash: types::unrequest_preimage::Hash, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Vesting", - "merge_schedules", - types::MergeSchedules { schedule1_index, schedule2_index }, + "Preimage", + "unrequest_preimage", + types::UnrequestPreimage { hash }, [ - 45u8, 24u8, 13u8, 108u8, 26u8, 99u8, 61u8, 117u8, 195u8, 218u8, 182u8, - 23u8, 188u8, 157u8, 181u8, 81u8, 38u8, 136u8, 31u8, 226u8, 8u8, 190u8, - 33u8, 81u8, 86u8, 185u8, 156u8, 77u8, 157u8, 197u8, 41u8, 58u8, + 55u8, 37u8, 224u8, 149u8, 142u8, 120u8, 8u8, 68u8, 183u8, 225u8, 255u8, + 240u8, 254u8, 111u8, 58u8, 200u8, 113u8, 217u8, 177u8, 203u8, 107u8, + 104u8, 233u8, 87u8, 252u8, 53u8, 33u8, 112u8, 116u8, 254u8, 117u8, + 134u8, ], ) } - #[doc = "Force remove a vesting schedule"] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Root_."] + #[doc = "Ensure that the bulk of pre-images is upgraded."] #[doc = ""] - #[doc = "- `target`: An account that has a vesting schedule"] - #[doc = "- `schedule_index`: The vesting schedule index that should be removed"] - pub fn force_remove_vesting_schedule( + #[doc = "The caller pays no fee if at least 90% of pre-images were successfully updated."] + pub fn ensure_updated( &self, - target: types::force_remove_vesting_schedule::Target, - schedule_index: types::force_remove_vesting_schedule::ScheduleIndex, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload< - types::ForceRemoveVestingSchedule, - > { + hashes: types::ensure_updated::Hashes, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Vesting", - "force_remove_vesting_schedule", - types::ForceRemoveVestingSchedule { target, schedule_index }, + "Preimage", + "ensure_updated", + types::EnsureUpdated { hashes }, [ - 211u8, 253u8, 60u8, 15u8, 20u8, 53u8, 23u8, 13u8, 45u8, 223u8, 136u8, - 183u8, 162u8, 143u8, 196u8, 188u8, 35u8, 64u8, 174u8, 16u8, 47u8, 13u8, - 147u8, 173u8, 120u8, 143u8, 75u8, 89u8, 128u8, 187u8, 9u8, 18u8, + 254u8, 228u8, 88u8, 44u8, 126u8, 235u8, 188u8, 153u8, 61u8, 27u8, + 103u8, 253u8, 163u8, 161u8, 113u8, 243u8, 87u8, 136u8, 2u8, 231u8, + 209u8, 188u8, 215u8, 106u8, 192u8, 225u8, 75u8, 125u8, 224u8, 96u8, + 221u8, 90u8, ], ) } } } #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_vesting::pallet::Event; + pub type Event = runtime_types::pallet_preimage::pallet::Event; pub mod events { use super::runtime_types; #[derive( @@ -6488,19 +6336,17 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A vesting schedule has been created."] - pub struct VestingCreated { - pub account: vesting_created::Account, - pub schedule_index: vesting_created::ScheduleIndex, + #[doc = "A preimage has been noted."] + pub struct Noted { + pub hash: noted::Hash, } - pub mod vesting_created { + pub mod noted { use super::runtime_types; - pub type Account = ::subxt::ext::subxt_core::utils::AccountId32; - pub type ScheduleIndex = ::core::primitive::u32; + pub type Hash = ::subxt::ext::subxt_core::utils::H256; } - impl ::subxt::ext::subxt_core::events::StaticEvent for VestingCreated { - const PALLET: &'static str = "Vesting"; - const EVENT: &'static str = "VestingCreated"; + impl ::subxt::ext::subxt_core::events::StaticEvent for Noted { + const PALLET: &'static str = "Preimage"; + const EVENT: &'static str = "Noted"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6509,20 +6355,17 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "The amount vested has been updated. This could indicate a change in funds available."] - #[doc = "The balance given is the amount which is left unvested (and thus locked)."] - pub struct VestingUpdated { - pub account: vesting_updated::Account, - pub unvested: vesting_updated::Unvested, + #[doc = "A preimage has been requested."] + pub struct Requested { + pub hash: requested::Hash, } - pub mod vesting_updated { + pub mod requested { use super::runtime_types; - pub type Account = ::subxt::ext::subxt_core::utils::AccountId32; - pub type Unvested = ::core::primitive::u128; + pub type Hash = ::subxt::ext::subxt_core::utils::H256; } - impl ::subxt::ext::subxt_core::events::StaticEvent for VestingUpdated { - const PALLET: &'static str = "Vesting"; - const EVENT: &'static str = "VestingUpdated"; + impl ::subxt::ext::subxt_core::events::StaticEvent for Requested { + const PALLET: &'static str = "Preimage"; + const EVENT: &'static str = "Requested"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6531,157 +6374,199 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "An \\[account\\] has become fully vested."] - pub struct VestingCompleted { - pub account: vesting_completed::Account, + #[doc = "A preimage has ben cleared."] + pub struct Cleared { + pub hash: cleared::Hash, } - pub mod vesting_completed { + pub mod cleared { use super::runtime_types; - pub type Account = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Hash = ::subxt::ext::subxt_core::utils::H256; } - impl ::subxt::ext::subxt_core::events::StaticEvent for VestingCompleted { - const PALLET: &'static str = "Vesting"; - const EVENT: &'static str = "VestingCompleted"; + impl ::subxt::ext::subxt_core::events::StaticEvent for Cleared { + const PALLET: &'static str = "Preimage"; + const EVENT: &'static str = "Cleared"; } } pub mod storage { use super::runtime_types; pub mod types { use super::runtime_types; - pub mod vesting { + pub mod status_for { use super::runtime_types; - pub type Vesting = runtime_types::bounded_collections::bounded_vec::BoundedVec< - runtime_types::pallet_vesting::vesting_info::VestingInfo< - ::core::primitive::u128, - ::core::primitive::u32, - >, + pub type StatusFor = runtime_types::pallet_preimage::OldRequestStatus< + ::subxt::ext::subxt_core::utils::AccountId32, + ::core::primitive::u128, >; - pub type Param0 = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Param0 = ::subxt::ext::subxt_core::utils::H256; } - pub mod storage_version { + pub mod request_status_for { + use super::runtime_types; + pub type RequestStatusFor = runtime_types::pallet_preimage::RequestStatus< + ::subxt::ext::subxt_core::utils::AccountId32, + runtime_types::quantus_runtime::governance::definitions::PreimageDeposit, + >; + pub type Param0 = ::subxt::ext::subxt_core::utils::H256; + } + pub mod preimage_for { use super::runtime_types; - pub type StorageVersion = runtime_types::pallet_vesting::Releases; + pub type PreimageFor = + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u8, + >; + pub type Param0 = + (::subxt::ext::subxt_core::utils::H256, ::core::primitive::u32); } } pub struct StorageApi; impl StorageApi { - #[doc = " Information regarding the vesting of a given account."] - pub fn vesting_iter( + #[doc = " The request status of a given hash."] + pub fn status_for_iter( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< (), - types::vesting::Vesting, + types::status_for::StatusFor, (), (), ::subxt::ext::subxt_core::utils::Yes, > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Vesting", - "Vesting", + "Preimage", + "StatusFor", (), [ - 95u8, 168u8, 217u8, 248u8, 149u8, 86u8, 195u8, 93u8, 73u8, 206u8, - 105u8, 165u8, 33u8, 173u8, 232u8, 81u8, 147u8, 254u8, 50u8, 228u8, - 156u8, 92u8, 242u8, 149u8, 42u8, 91u8, 58u8, 209u8, 142u8, 221u8, - 230u8, 112u8, + 187u8, 100u8, 54u8, 112u8, 96u8, 129u8, 36u8, 149u8, 127u8, 226u8, + 126u8, 171u8, 72u8, 189u8, 59u8, 126u8, 204u8, 125u8, 67u8, 204u8, + 231u8, 6u8, 212u8, 135u8, 166u8, 252u8, 5u8, 46u8, 111u8, 120u8, 54u8, + 209u8, ], ) } - #[doc = " Information regarding the vesting of a given account."] - pub fn vesting( + #[doc = " The request status of a given hash."] + pub fn status_for( &self, - _0: types::vesting::Param0, + _0: types::status_for::Param0, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::vesting::Param0, + types::status_for::Param0, >, - types::vesting::Vesting, + types::status_for::StatusFor, ::subxt::ext::subxt_core::utils::Yes, (), (), > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Vesting", - "Vesting", + "Preimage", + "StatusFor", ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 95u8, 168u8, 217u8, 248u8, 149u8, 86u8, 195u8, 93u8, 73u8, 206u8, - 105u8, 165u8, 33u8, 173u8, 232u8, 81u8, 147u8, 254u8, 50u8, 228u8, - 156u8, 92u8, 242u8, 149u8, 42u8, 91u8, 58u8, 209u8, 142u8, 221u8, - 230u8, 112u8, + 187u8, 100u8, 54u8, 112u8, 96u8, 129u8, 36u8, 149u8, 127u8, 226u8, + 126u8, 171u8, 72u8, 189u8, 59u8, 126u8, 204u8, 125u8, 67u8, 204u8, + 231u8, 6u8, 212u8, 135u8, 166u8, 252u8, 5u8, 46u8, 111u8, 120u8, 54u8, + 209u8, ], ) } - #[doc = " Storage version of the pallet."] - #[doc = ""] - #[doc = " New networks start with latest version, as determined by the genesis build."] - pub fn storage_version( + #[doc = " The request status of a given hash."] + pub fn request_status_for_iter( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< (), - types::storage_version::StorageVersion, + types::request_status_for::RequestStatusFor, + (), + (), ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Preimage", + "RequestStatusFor", + (), + [ + 113u8, 195u8, 77u8, 23u8, 125u8, 170u8, 77u8, 145u8, 201u8, 168u8, + 39u8, 13u8, 143u8, 50u8, 100u8, 92u8, 25u8, 110u8, 125u8, 20u8, 96u8, + 156u8, 225u8, 200u8, 57u8, 199u8, 226u8, 242u8, 230u8, 126u8, 138u8, + 123u8, + ], + ) + } + #[doc = " The request status of a given hash."] + pub fn request_status_for( + &self, + _0: types::request_status_for::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::request_status_for::Param0, + >, + types::request_status_for::RequestStatusFor, ::subxt::ext::subxt_core::utils::Yes, (), + (), > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Vesting", - "StorageVersion", - (), + "Preimage", + "RequestStatusFor", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 230u8, 137u8, 180u8, 133u8, 142u8, 124u8, 231u8, 234u8, 223u8, 10u8, - 154u8, 98u8, 158u8, 253u8, 228u8, 80u8, 5u8, 9u8, 91u8, 210u8, 252u8, - 9u8, 13u8, 195u8, 193u8, 164u8, 129u8, 113u8, 128u8, 218u8, 8u8, 40u8, + 113u8, 195u8, 77u8, 23u8, 125u8, 170u8, 77u8, 145u8, 201u8, 168u8, + 39u8, 13u8, 143u8, 50u8, 100u8, 92u8, 25u8, 110u8, 125u8, 20u8, 96u8, + 156u8, 225u8, 200u8, 57u8, 199u8, 226u8, 242u8, 230u8, 126u8, 138u8, + 123u8, ], ) } - } - } - pub mod constants { - use super::runtime_types; - pub struct ConstantsApi; - impl ConstantsApi { - #[doc = " The minimum amount transferred to call `vested_transfer`."] - pub fn min_vested_transfer( + pub fn preimage_for_iter( &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u128, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::preimage_for::PreimageFor, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Vesting", - "MinVestedTransfer", + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Preimage", + "PreimageFor", + (), [ - 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, - 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, - 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + 106u8, 5u8, 17u8, 46u8, 6u8, 184u8, 177u8, 113u8, 169u8, 34u8, 119u8, + 141u8, 117u8, 40u8, 30u8, 94u8, 187u8, 35u8, 206u8, 216u8, 143u8, + 208u8, 49u8, 156u8, 200u8, 255u8, 109u8, 200u8, 210u8, 134u8, 24u8, + 139u8, ], ) } - pub fn max_vesting_schedules( + pub fn preimage_for( &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u32, + _0: types::preimage_for::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::preimage_for::Param0, + >, + types::preimage_for::PreimageFor, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Vesting", - "MaxVestingSchedules", + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Preimage", + "PreimageFor", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, + 106u8, 5u8, 17u8, 46u8, 6u8, 184u8, 177u8, 113u8, 169u8, 34u8, 119u8, + 141u8, 117u8, 40u8, 30u8, 94u8, 187u8, 35u8, 206u8, 216u8, 143u8, + 208u8, 49u8, 156u8, 200u8, 255u8, 109u8, 200u8, 210u8, 134u8, 24u8, + 139u8, ], ) } } } } - pub mod preimage { + pub mod scheduler { use super::{root_mod, runtime_types}; #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_preimage::pallet::Error; + pub type Error = runtime_types::pallet_scheduler::pallet::Error; #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_preimage::pallet::Call; + pub type Call = runtime_types::pallet_scheduler::pallet::Call; pub mod calls { use super::{root_mod, runtime_types}; type DispatchError = runtime_types::sp_runtime::DispatchError; @@ -6698,21 +6583,29 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Register a preimage on-chain."] - #[doc = ""] - #[doc = "If the preimage was previously requested, no fees or deposits are taken for providing"] - #[doc = "the preimage. Otherwise, a deposit is taken proportional to the size of the preimage."] - pub struct NotePreimage { - pub bytes: note_preimage::Bytes, + #[doc = "Anonymously schedule a task."] + pub struct Schedule { + pub when: schedule::When, + pub maybe_periodic: schedule::MaybePeriodic, + pub priority: schedule::Priority, + pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, } - pub mod note_preimage { + pub mod schedule { use super::runtime_types; - pub type Bytes = - ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>; + pub type When = ::core::primitive::u32; + pub type MaybePeriodic = ::core::option::Option<( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + ::core::primitive::u32, + )>; + pub type Priority = ::core::primitive::u8; + pub type Call = runtime_types::quantus_runtime::RuntimeCall; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for NotePreimage { - const PALLET: &'static str = "Preimage"; - const CALL: &'static str = "note_preimage"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Schedule { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "schedule"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6725,22 +6618,22 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Clear an unrequested preimage from the runtime storage."] - #[doc = ""] - #[doc = "If `len` is provided, then it will be a much cheaper operation."] - #[doc = ""] - #[doc = "- `hash`: The hash of the preimage to be removed from the store."] - #[doc = "- `len`: The length of the preimage of `hash`."] - pub struct UnnotePreimage { - pub hash: unnote_preimage::Hash, + #[doc = "Cancel an anonymously scheduled task."] + pub struct Cancel { + pub when: cancel::When, + pub index: cancel::Index, } - pub mod unnote_preimage { + pub mod cancel { use super::runtime_types; - pub type Hash = ::subxt::ext::subxt_core::utils::H256; + pub type When = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >; + pub type Index = ::core::primitive::u32; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for UnnotePreimage { - const PALLET: &'static str = "Preimage"; - const CALL: &'static str = "unnote_preimage"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Cancel { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "cancel"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6753,20 +6646,31 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Request a preimage be uploaded to the chain without paying any fees or deposits."] - #[doc = ""] - #[doc = "If the preimage requests has already been provided on-chain, we unreserve any deposit"] - #[doc = "a user may have paid, and take the control of the preimage out of their hands."] - pub struct RequestPreimage { - pub hash: request_preimage::Hash, + #[doc = "Schedule a named task."] + pub struct ScheduleNamed { + pub id: schedule_named::Id, + pub when: schedule_named::When, + pub maybe_periodic: schedule_named::MaybePeriodic, + pub priority: schedule_named::Priority, + pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, } - pub mod request_preimage { + pub mod schedule_named { use super::runtime_types; - pub type Hash = ::subxt::ext::subxt_core::utils::H256; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for RequestPreimage { - const PALLET: &'static str = "Preimage"; - const CALL: &'static str = "request_preimage"; + pub type Id = [::core::primitive::u8; 32usize]; + pub type When = ::core::primitive::u32; + pub type MaybePeriodic = ::core::option::Option<( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + ::core::primitive::u32, + )>; + pub type Priority = ::core::primitive::u8; + pub type Call = runtime_types::quantus_runtime::RuntimeCall; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ScheduleNamed { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "schedule_named"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6779,19 +6683,17 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Clear a previously made request for a preimage."] - #[doc = ""] - #[doc = "NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`."] - pub struct UnrequestPreimage { - pub hash: unrequest_preimage::Hash, + #[doc = "Cancel a named scheduled task."] + pub struct CancelNamed { + pub id: cancel_named::Id, } - pub mod unrequest_preimage { + pub mod cancel_named { use super::runtime_types; - pub type Hash = ::subxt::ext::subxt_core::utils::H256; + pub type Id = [::core::primitive::u8; 32usize]; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for UnrequestPreimage { - const PALLET: &'static str = "Preimage"; - const CALL: &'static str = "unrequest_preimage"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CancelNamed { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "cancel_named"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -6804,1562 +6706,1204 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Ensure that the bulk of pre-images is upgraded."] - #[doc = ""] - #[doc = "The caller pays no fee if at least 90% of pre-images were successfully updated."] - pub struct EnsureUpdated { - pub hashes: ensure_updated::Hashes, + #[doc = "Anonymously schedule a task after a delay."] + pub struct ScheduleAfter { + pub after: schedule_after::After, + pub maybe_periodic: schedule_after::MaybePeriodic, + pub priority: schedule_after::Priority, + pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, } - pub mod ensure_updated { + pub mod schedule_after { use super::runtime_types; - pub type Hashes = ::subxt::ext::subxt_core::alloc::vec::Vec< - ::subxt::ext::subxt_core::utils::H256, + pub type After = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, >; + pub type MaybePeriodic = ::core::option::Option<( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + ::core::primitive::u32, + )>; + pub type Priority = ::core::primitive::u8; + pub type Call = runtime_types::quantus_runtime::RuntimeCall; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for EnsureUpdated { - const PALLET: &'static str = "Preimage"; - const CALL: &'static str = "ensure_updated"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ScheduleAfter { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "schedule_after"; } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "Register a preimage on-chain."] - #[doc = ""] - #[doc = "If the preimage was previously requested, no fees or deposits are taken for providing"] - #[doc = "the preimage. Otherwise, a deposit is taken proportional to the size of the preimage."] - pub fn note_preimage( - &self, - bytes: types::note_preimage::Bytes, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Preimage", - "note_preimage", - types::NotePreimage { bytes }, - [ - 121u8, 88u8, 18u8, 92u8, 176u8, 15u8, 192u8, 198u8, 146u8, 198u8, 38u8, - 242u8, 213u8, 83u8, 7u8, 230u8, 14u8, 110u8, 235u8, 32u8, 215u8, 26u8, - 192u8, 217u8, 113u8, 224u8, 206u8, 96u8, 177u8, 198u8, 246u8, 33u8, - ], - ) + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Schedule a named task after a delay."] + pub struct ScheduleNamedAfter { + pub id: schedule_named_after::Id, + pub after: schedule_named_after::After, + pub maybe_periodic: schedule_named_after::MaybePeriodic, + pub priority: schedule_named_after::Priority, + pub call: + ::subxt::ext::subxt_core::alloc::boxed::Box, } - #[doc = "Clear an unrequested preimage from the runtime storage."] + pub mod schedule_named_after { + use super::runtime_types; + pub type Id = [::core::primitive::u8; 32usize]; + pub type After = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >; + pub type MaybePeriodic = ::core::option::Option<( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + ::core::primitive::u32, + )>; + pub type Priority = ::core::primitive::u8; + pub type Call = runtime_types::quantus_runtime::RuntimeCall; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ScheduleNamedAfter { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "schedule_named_after"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Set a retry configuration for a task so that, in case its scheduled run fails, it will"] + #[doc = "be retried after `period` blocks, for a total amount of `retries` retries or until it"] + #[doc = "succeeds."] #[doc = ""] - #[doc = "If `len` is provided, then it will be a much cheaper operation."] + #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] + #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] + #[doc = "normally while the task is retrying."] #[doc = ""] - #[doc = "- `hash`: The hash of the preimage to be removed from the store."] - #[doc = "- `len`: The length of the preimage of `hash`."] - pub fn unnote_preimage( - &self, - hash: types::unnote_preimage::Hash, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Preimage", - "unnote_preimage", - types::UnnotePreimage { hash }, - [ - 188u8, 116u8, 222u8, 22u8, 127u8, 215u8, 2u8, 133u8, 96u8, 202u8, - 190u8, 123u8, 203u8, 43u8, 200u8, 161u8, 226u8, 24u8, 49u8, 36u8, - 221u8, 160u8, 130u8, 119u8, 30u8, 138u8, 144u8, 85u8, 5u8, 164u8, - 252u8, 222u8, - ], - ) + #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "clones of the original task. Their retry configuration will be derived from the"] + #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] + #[doc = "original `total_retries`."] + pub struct SetRetry { + pub task: set_retry::Task, + pub retries: set_retry::Retries, + pub period: set_retry::Period, } - #[doc = "Request a preimage be uploaded to the chain without paying any fees or deposits."] - #[doc = ""] - #[doc = "If the preimage requests has already been provided on-chain, we unreserve any deposit"] - #[doc = "a user may have paid, and take the control of the preimage out of their hands."] - pub fn request_preimage( - &self, - hash: types::request_preimage::Hash, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Preimage", - "request_preimage", - types::RequestPreimage { hash }, - [ - 87u8, 0u8, 204u8, 111u8, 43u8, 115u8, 64u8, 209u8, 133u8, 13u8, 83u8, - 45u8, 164u8, 166u8, 233u8, 105u8, 242u8, 238u8, 235u8, 208u8, 113u8, - 134u8, 93u8, 242u8, 86u8, 32u8, 7u8, 152u8, 107u8, 208u8, 79u8, 59u8, - ], - ) + pub mod set_retry { + use super::runtime_types; + pub type Task = ( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + ::core::primitive::u32, + ); + pub type Retries = ::core::primitive::u8; + pub type Period = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >; } - #[doc = "Clear a previously made request for a preimage."] - #[doc = ""] - #[doc = "NOTE: THIS MUST NOT BE CALLED ON `hash` MORE TIMES THAN `request_preimage`."] - pub fn unrequest_preimage( - &self, - hash: types::unrequest_preimage::Hash, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Preimage", - "unrequest_preimage", - types::UnrequestPreimage { hash }, - [ - 55u8, 37u8, 224u8, 149u8, 142u8, 120u8, 8u8, 68u8, 183u8, 225u8, 255u8, - 240u8, 254u8, 111u8, 58u8, 200u8, 113u8, 217u8, 177u8, 203u8, 107u8, - 104u8, 233u8, 87u8, 252u8, 53u8, 33u8, 112u8, 116u8, 254u8, 117u8, - 134u8, - ], - ) + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SetRetry { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "set_retry"; } - #[doc = "Ensure that the bulk of pre-images is upgraded."] + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Set a retry configuration for a named task so that, in case its scheduled run fails, it"] + #[doc = "will be retried after `period` blocks, for a total amount of `retries` retries or until"] + #[doc = "it succeeds."] #[doc = ""] - #[doc = "The caller pays no fee if at least 90% of pre-images were successfully updated."] - pub fn ensure_updated( - &self, - hashes: types::ensure_updated::Hashes, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Preimage", - "ensure_updated", - types::EnsureUpdated { hashes }, - [ - 254u8, 228u8, 88u8, 44u8, 126u8, 235u8, 188u8, 153u8, 61u8, 27u8, - 103u8, 253u8, 163u8, 161u8, 113u8, 243u8, 87u8, 136u8, 2u8, 231u8, - 209u8, 188u8, 215u8, 106u8, 192u8, 225u8, 75u8, 125u8, 224u8, 96u8, - 221u8, 90u8, - ], - ) - } - } - } - #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_preimage::pallet::Event; - pub mod events { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A preimage has been noted."] - pub struct Noted { - pub hash: noted::Hash, - } - pub mod noted { - use super::runtime_types; - pub type Hash = ::subxt::ext::subxt_core::utils::H256; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Noted { - const PALLET: &'static str = "Preimage"; - const EVENT: &'static str = "Noted"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A preimage has been requested."] - pub struct Requested { - pub hash: requested::Hash, - } - pub mod requested { - use super::runtime_types; - pub type Hash = ::subxt::ext::subxt_core::utils::H256; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Requested { - const PALLET: &'static str = "Preimage"; - const EVENT: &'static str = "Requested"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A preimage has ben cleared."] - pub struct Cleared { - pub hash: cleared::Hash, - } - pub mod cleared { - use super::runtime_types; - pub type Hash = ::subxt::ext::subxt_core::utils::H256; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Cleared { - const PALLET: &'static str = "Preimage"; - const EVENT: &'static str = "Cleared"; - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod status_for { + #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] + #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] + #[doc = "normally while the task is retrying."] + #[doc = ""] + #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "clones of the original task. Their retry configuration will be derived from the"] + #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] + #[doc = "original `total_retries`."] + pub struct SetRetryNamed { + pub id: set_retry_named::Id, + pub retries: set_retry_named::Retries, + pub period: set_retry_named::Period, + } + pub mod set_retry_named { use super::runtime_types; - pub type StatusFor = runtime_types::pallet_preimage::OldRequestStatus< - ::subxt::ext::subxt_core::utils::AccountId32, - ::core::primitive::u128, + pub type Id = [::core::primitive::u8; 32usize]; + pub type Retries = ::core::primitive::u8; + pub type Period = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, >; - pub type Param0 = ::subxt::ext::subxt_core::utils::H256; } - pub mod request_status_for { + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SetRetryNamed { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "set_retry_named"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Removes the retry configuration of a task."] + pub struct CancelRetry { + pub task: cancel_retry::Task, + } + pub mod cancel_retry { use super::runtime_types; - pub type RequestStatusFor = runtime_types::pallet_preimage::RequestStatus< - ::subxt::ext::subxt_core::utils::AccountId32, - runtime_types::quantus_runtime::governance::definitions::PreimageDeposit, - >; - pub type Param0 = ::subxt::ext::subxt_core::utils::H256; + pub type Task = ( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + ::core::primitive::u32, + ); } - pub mod preimage_for { + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CancelRetry { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "cancel_retry"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Cancel the retry configuration of a named task."] + pub struct CancelRetryNamed { + pub id: cancel_retry_named::Id, + } + pub mod cancel_retry_named { use super::runtime_types; - pub type PreimageFor = - runtime_types::bounded_collections::bounded_vec::BoundedVec< - ::core::primitive::u8, - >; - pub type Param0 = - (::subxt::ext::subxt_core::utils::H256, ::core::primitive::u32); + pub type Id = [::core::primitive::u8; 32usize]; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CancelRetryNamed { + const PALLET: &'static str = "Scheduler"; + const CALL: &'static str = "cancel_retry_named"; } } - pub struct StorageApi; - impl StorageApi { - #[doc = " The request status of a given hash."] - pub fn status_for_iter( + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Anonymously schedule a task."] + pub fn schedule( &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::status_for::StatusFor, - (), - (), - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Preimage", - "StatusFor", - (), + when: types::schedule::When, + maybe_periodic: types::schedule::MaybePeriodic, + priority: types::schedule::Priority, + call: types::schedule::Call, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "schedule", + types::Schedule { + when, + maybe_periodic, + priority, + call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), + }, [ - 187u8, 100u8, 54u8, 112u8, 96u8, 129u8, 36u8, 149u8, 127u8, 226u8, - 126u8, 171u8, 72u8, 189u8, 59u8, 126u8, 204u8, 125u8, 67u8, 204u8, - 231u8, 6u8, 212u8, 135u8, 166u8, 252u8, 5u8, 46u8, 111u8, 120u8, 54u8, - 209u8, + 102u8, 103u8, 19u8, 115u8, 19u8, 43u8, 141u8, 147u8, 145u8, 130u8, + 118u8, 205u8, 116u8, 21u8, 169u8, 245u8, 91u8, 195u8, 69u8, 49u8, 11u8, + 189u8, 250u8, 142u8, 248u8, 124u8, 135u8, 217u8, 78u8, 252u8, 36u8, + 226u8, ], ) } - #[doc = " The request status of a given hash."] - pub fn status_for( + #[doc = "Cancel an anonymously scheduled task."] + pub fn cancel( &self, - _0: types::status_for::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::status_for::Param0, - >, - types::status_for::StatusFor, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Preimage", - "StatusFor", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + when: types::cancel::When, + index: types::cancel::Index, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "cancel", + types::Cancel { when, index }, [ - 187u8, 100u8, 54u8, 112u8, 96u8, 129u8, 36u8, 149u8, 127u8, 226u8, - 126u8, 171u8, 72u8, 189u8, 59u8, 126u8, 204u8, 125u8, 67u8, 204u8, - 231u8, 6u8, 212u8, 135u8, 166u8, 252u8, 5u8, 46u8, 111u8, 120u8, 54u8, - 209u8, + 134u8, 77u8, 15u8, 56u8, 137u8, 12u8, 58u8, 147u8, 164u8, 204u8, 221u8, + 150u8, 103u8, 42u8, 36u8, 79u8, 146u8, 115u8, 13u8, 194u8, 39u8, 73u8, + 109u8, 10u8, 168u8, 164u8, 190u8, 173u8, 30u8, 17u8, 35u8, 17u8, ], ) } - #[doc = " The request status of a given hash."] - pub fn request_status_for_iter( + #[doc = "Schedule a named task."] + pub fn schedule_named( &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::request_status_for::RequestStatusFor, - (), - (), - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Preimage", - "RequestStatusFor", - (), + id: types::schedule_named::Id, + when: types::schedule_named::When, + maybe_periodic: types::schedule_named::MaybePeriodic, + priority: types::schedule_named::Priority, + call: types::schedule_named::Call, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "schedule_named", + types::ScheduleNamed { + id, + when, + maybe_periodic, + priority, + call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), + }, [ - 113u8, 195u8, 77u8, 23u8, 125u8, 170u8, 77u8, 145u8, 201u8, 168u8, - 39u8, 13u8, 143u8, 50u8, 100u8, 92u8, 25u8, 110u8, 125u8, 20u8, 96u8, - 156u8, 225u8, 200u8, 57u8, 199u8, 226u8, 242u8, 230u8, 126u8, 138u8, - 123u8, + 138u8, 207u8, 16u8, 247u8, 167u8, 103u8, 166u8, 249u8, 84u8, 160u8, + 115u8, 250u8, 241u8, 153u8, 56u8, 116u8, 81u8, 181u8, 152u8, 239u8, + 95u8, 135u8, 69u8, 165u8, 228u8, 216u8, 227u8, 71u8, 157u8, 114u8, + 117u8, 192u8, ], ) } - #[doc = " The request status of a given hash."] - pub fn request_status_for( + #[doc = "Cancel a named scheduled task."] + pub fn cancel_named( &self, - _0: types::request_status_for::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::request_status_for::Param0, - >, - types::request_status_for::RequestStatusFor, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Preimage", - "RequestStatusFor", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + id: types::cancel_named::Id, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "cancel_named", + types::CancelNamed { id }, [ - 113u8, 195u8, 77u8, 23u8, 125u8, 170u8, 77u8, 145u8, 201u8, 168u8, - 39u8, 13u8, 143u8, 50u8, 100u8, 92u8, 25u8, 110u8, 125u8, 20u8, 96u8, - 156u8, 225u8, 200u8, 57u8, 199u8, 226u8, 242u8, 230u8, 126u8, 138u8, - 123u8, + 205u8, 35u8, 28u8, 57u8, 224u8, 7u8, 49u8, 233u8, 236u8, 163u8, 93u8, + 236u8, 103u8, 69u8, 65u8, 51u8, 121u8, 84u8, 9u8, 196u8, 147u8, 122u8, + 227u8, 200u8, 181u8, 233u8, 62u8, 240u8, 174u8, 83u8, 129u8, 193u8, ], ) } - pub fn preimage_for_iter( + #[doc = "Anonymously schedule a task after a delay."] + pub fn schedule_after( &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::preimage_for::PreimageFor, - (), - (), - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Preimage", - "PreimageFor", - (), + after: types::schedule_after::After, + maybe_periodic: types::schedule_after::MaybePeriodic, + priority: types::schedule_after::Priority, + call: types::schedule_after::Call, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "schedule_after", + types::ScheduleAfter { + after, + maybe_periodic, + priority, + call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), + }, [ - 106u8, 5u8, 17u8, 46u8, 6u8, 184u8, 177u8, 113u8, 169u8, 34u8, 119u8, - 141u8, 117u8, 40u8, 30u8, 94u8, 187u8, 35u8, 206u8, 216u8, 143u8, - 208u8, 49u8, 156u8, 200u8, 255u8, 109u8, 200u8, 210u8, 134u8, 24u8, - 139u8, + 229u8, 249u8, 88u8, 250u8, 31u8, 188u8, 238u8, 42u8, 94u8, 153u8, 29u8, + 70u8, 199u8, 95u8, 46u8, 113u8, 204u8, 236u8, 225u8, 200u8, 34u8, 55u8, + 82u8, 32u8, 14u8, 154u8, 73u8, 175u8, 205u8, 6u8, 165u8, 72u8, ], ) } - pub fn preimage_for( + #[doc = "Schedule a named task after a delay."] + pub fn schedule_named_after( &self, - _0: types::preimage_for::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::preimage_for::Param0, - >, - types::preimage_for::PreimageFor, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Preimage", - "PreimageFor", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + id: types::schedule_named_after::Id, + after: types::schedule_named_after::After, + maybe_periodic: types::schedule_named_after::MaybePeriodic, + priority: types::schedule_named_after::Priority, + call: types::schedule_named_after::Call, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "schedule_named_after", + types::ScheduleNamedAfter { + id, + after, + maybe_periodic, + priority, + call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), + }, [ - 106u8, 5u8, 17u8, 46u8, 6u8, 184u8, 177u8, 113u8, 169u8, 34u8, 119u8, - 141u8, 117u8, 40u8, 30u8, 94u8, 187u8, 35u8, 206u8, 216u8, 143u8, - 208u8, 49u8, 156u8, 200u8, 255u8, 109u8, 200u8, 210u8, 134u8, 24u8, - 139u8, + 171u8, 36u8, 101u8, 188u8, 133u8, 123u8, 205u8, 135u8, 23u8, 2u8, 7u8, + 96u8, 10u8, 38u8, 102u8, 157u8, 170u8, 113u8, 223u8, 3u8, 144u8, 47u8, + 168u8, 57u8, 167u8, 12u8, 195u8, 66u8, 158u8, 250u8, 66u8, 157u8, ], ) } - } - } - } - pub mod scheduler { - use super::{root_mod, runtime_types}; - #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_scheduler::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_scheduler::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Anonymously schedule a task."] - pub struct Schedule { - pub when: schedule::When, - pub maybe_periodic: schedule::MaybePeriodic, - pub priority: schedule::Priority, - pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, + #[doc = "Set a retry configuration for a task so that, in case its scheduled run fails, it will"] + #[doc = "be retried after `period` blocks, for a total amount of `retries` retries or until it"] + #[doc = "succeeds."] + #[doc = ""] + #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] + #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] + #[doc = "normally while the task is retrying."] + #[doc = ""] + #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "clones of the original task. Their retry configuration will be derived from the"] + #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] + #[doc = "original `total_retries`."] + pub fn set_retry( + &self, + task: types::set_retry::Task, + retries: types::set_retry::Retries, + period: types::set_retry::Period, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "set_retry", + types::SetRetry { task, retries, period }, + [ + 31u8, 128u8, 255u8, 13u8, 13u8, 252u8, 74u8, 151u8, 60u8, 242u8, 152u8, + 58u8, 190u8, 155u8, 132u8, 65u8, 139u8, 208u8, 222u8, 175u8, 89u8, + 222u8, 186u8, 98u8, 53u8, 125u8, 71u8, 55u8, 95u8, 2u8, 76u8, 248u8, + ], + ) } - pub mod schedule { - use super::runtime_types; - pub type When = ::core::primitive::u32; - pub type MaybePeriodic = ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - )>; - pub type Priority = ::core::primitive::u8; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; + #[doc = "Set a retry configuration for a named task so that, in case its scheduled run fails, it"] + #[doc = "will be retried after `period` blocks, for a total amount of `retries` retries or until"] + #[doc = "it succeeds."] + #[doc = ""] + #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] + #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] + #[doc = "normally while the task is retrying."] + #[doc = ""] + #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "clones of the original task. Their retry configuration will be derived from the"] + #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] + #[doc = "original `total_retries`."] + pub fn set_retry_named( + &self, + id: types::set_retry_named::Id, + retries: types::set_retry_named::Retries, + period: types::set_retry_named::Period, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "set_retry_named", + types::SetRetryNamed { id, retries, period }, + [ + 102u8, 70u8, 114u8, 48u8, 180u8, 194u8, 107u8, 81u8, 104u8, 117u8, + 33u8, 169u8, 43u8, 172u8, 61u8, 129u8, 143u8, 221u8, 44u8, 101u8, + 235u8, 228u8, 224u8, 71u8, 65u8, 223u8, 180u8, 130u8, 83u8, 89u8, + 157u8, 75u8, + ], + ) } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Schedule { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "schedule"; + #[doc = "Removes the retry configuration of a task."] + pub fn cancel_retry( + &self, + task: types::cancel_retry::Task, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "cancel_retry", + types::CancelRetry { task }, + [ + 153u8, 252u8, 168u8, 142u8, 100u8, 114u8, 25u8, 46u8, 225u8, 95u8, + 243u8, 78u8, 160u8, 175u8, 17u8, 33u8, 27u8, 241u8, 149u8, 187u8, + 228u8, 182u8, 233u8, 74u8, 10u8, 228u8, 117u8, 218u8, 210u8, 127u8, + 245u8, 105u8, + ], + ) } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Cancel an anonymously scheduled task."] - pub struct Cancel { - pub when: cancel::When, - pub index: cancel::Index, + #[doc = "Cancel the retry configuration of a named task."] + pub fn cancel_retry_named( + &self, + id: types::cancel_retry_named::Id, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Scheduler", + "cancel_retry_named", + types::CancelRetryNamed { id }, + [ + 76u8, 157u8, 253u8, 113u8, 162u8, 54u8, 98u8, 21u8, 62u8, 44u8, 155u8, + 202u8, 2u8, 28u8, 153u8, 219u8, 67u8, 166u8, 206u8, 79u8, 139u8, 3u8, + 119u8, 182u8, 254u8, 134u8, 143u8, 121u8, 155u8, 220u8, 192u8, 209u8, + ], + ) } - pub mod cancel { - use super::runtime_types; - pub type When = runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, + } + } + #[doc = "Events type."] + pub type Event = runtime_types::pallet_scheduler::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Scheduled some task."] + pub struct Scheduled { + pub when: scheduled::When, + pub index: scheduled::Index, + } + pub mod scheduled { + use super::runtime_types; + pub type When = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >; + pub type Index = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for Scheduled { + const PALLET: &'static str = "Scheduler"; + const EVENT: &'static str = "Scheduled"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Canceled some task."] + pub struct Canceled { + pub when: canceled::When, + pub index: canceled::Index, + } + pub mod canceled { + use super::runtime_types; + pub type When = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >; + pub type Index = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for Canceled { + const PALLET: &'static str = "Scheduler"; + const EVENT: &'static str = "Canceled"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Dispatched some task."] + pub struct Dispatched { + pub task: dispatched::Task, + pub id: dispatched::Id, + pub result: dispatched::Result, + } + pub mod dispatched { + use super::runtime_types; + pub type Task = ( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, ::core::primitive::u64, - >; - pub type Index = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Cancel { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "cancel"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Schedule a named task."] - pub struct ScheduleNamed { - pub id: schedule_named::Id, - pub when: schedule_named::When, - pub maybe_periodic: schedule_named::MaybePeriodic, - pub priority: schedule_named::Priority, - pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, - } - pub mod schedule_named { - use super::runtime_types; - pub type Id = [::core::primitive::u8; 32usize]; - pub type When = ::core::primitive::u32; - pub type MaybePeriodic = ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, + >, + ::core::primitive::u32, + ); + pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; + pub type Result = + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for Dispatched { + const PALLET: &'static str = "Scheduler"; + const EVENT: &'static str = "Dispatched"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Set a retry configuration for some task."] + pub struct RetrySet { + pub task: retry_set::Task, + pub id: retry_set::Id, + pub period: retry_set::Period, + pub retries: retry_set::Retries, + } + pub mod retry_set { + use super::runtime_types; + pub type Task = ( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< ::core::primitive::u32, - )>; - pub type Priority = ::core::primitive::u8; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ScheduleNamed { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "schedule_named"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Cancel a named scheduled task."] - pub struct CancelNamed { - pub id: cancel_named::Id, - } - pub mod cancel_named { - use super::runtime_types; - pub type Id = [::core::primitive::u8; 32usize]; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CancelNamed { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "cancel_named"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Anonymously schedule a task after a delay."] - pub struct ScheduleAfter { - pub after: schedule_after::After, - pub maybe_periodic: schedule_after::MaybePeriodic, - pub priority: schedule_after::Priority, - pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, - } - pub mod schedule_after { - use super::runtime_types; - pub type After = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u64, + >, + ::core::primitive::u32, + ); + pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; + pub type Period = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >; + pub type Retries = ::core::primitive::u8; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for RetrySet { + const PALLET: &'static str = "Scheduler"; + const EVENT: &'static str = "RetrySet"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Cancel a retry configuration for some task."] + pub struct RetryCancelled { + pub task: retry_cancelled::Task, + pub id: retry_cancelled::Id, + } + pub mod retry_cancelled { + use super::runtime_types; + pub type Task = ( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< ::core::primitive::u32, ::core::primitive::u64, - >; - pub type MaybePeriodic = ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, + >, + ::core::primitive::u32, + ); + pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for RetryCancelled { + const PALLET: &'static str = "Scheduler"; + const EVENT: &'static str = "RetryCancelled"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "The call for the provided hash was not found so the task has been aborted."] + pub struct CallUnavailable { + pub task: call_unavailable::Task, + pub id: call_unavailable::Id, + } + pub mod call_unavailable { + use super::runtime_types; + pub type Task = ( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< ::core::primitive::u32, - )>; - pub type Priority = ::core::primitive::u8; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ScheduleAfter { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "schedule_after"; + ::core::primitive::u64, + >, + ::core::primitive::u32, + ); + pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for CallUnavailable { + const PALLET: &'static str = "Scheduler"; + const EVENT: &'static str = "CallUnavailable"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "The given task was unable to be renewed since the agenda is full at that block."] + pub struct PeriodicFailed { + pub task: periodic_failed::Task, + pub id: periodic_failed::Id, + } + pub mod periodic_failed { + use super::runtime_types; + pub type Task = ( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + ::core::primitive::u32, + ); + pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for PeriodicFailed { + const PALLET: &'static str = "Scheduler"; + const EVENT: &'static str = "PeriodicFailed"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "The given task was unable to be retried since the agenda is full at that block or there"] + #[doc = "was not enough weight to reschedule it."] + pub struct RetryFailed { + pub task: retry_failed::Task, + pub id: retry_failed::Id, + } + pub mod retry_failed { + use super::runtime_types; + pub type Task = ( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + ::core::primitive::u32, + ); + pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for RetryFailed { + const PALLET: &'static str = "Scheduler"; + const EVENT: &'static str = "RetryFailed"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "The given task can never be executed since it is overweight."] + pub struct PermanentlyOverweight { + pub task: permanently_overweight::Task, + pub id: permanently_overweight::Id, + } + pub mod permanently_overweight { + use super::runtime_types; + pub type Task = ( + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + ::core::primitive::u32, + ); + pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for PermanentlyOverweight { + const PALLET: &'static str = "Scheduler"; + const EVENT: &'static str = "PermanentlyOverweight"; + } + } + pub mod storage { + use super::runtime_types; + pub mod types { + use super::runtime_types; + pub mod incomplete_block_since { + use super::runtime_types; + pub type IncompleteBlockSince = ::core::primitive::u32; } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Schedule a named task after a delay."] - pub struct ScheduleNamedAfter { - pub id: schedule_named_after::Id, - pub after: schedule_named_after::After, - pub maybe_periodic: schedule_named_after::MaybePeriodic, - pub priority: schedule_named_after::Priority, - pub call: - ::subxt::ext::subxt_core::alloc::boxed::Box, + pub mod incomplete_timestamp_since { + use super::runtime_types; + pub type IncompleteTimestampSince = ::core::primitive::u64; } - pub mod schedule_named_after { + pub mod last_processed_timestamp { use super::runtime_types; - pub type Id = [::core::primitive::u8; 32usize]; - pub type After = runtime_types::qp_scheduler::BlockNumberOrTimestamp< + pub type LastProcessedTimestamp = ::core::primitive::u64; + } + pub mod agenda { + use super::runtime_types; + pub type Agenda = runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::option::Option< + runtime_types::pallet_scheduler::Scheduled< + [::core::primitive::u8; 32usize], + runtime_types::frame_support::traits::preimages::Bounded< + runtime_types::quantus_runtime::RuntimeCall, + runtime_types::qp_poseidon::PoseidonHasher, + >, + ::core::primitive::u32, + runtime_types::quantus_runtime::OriginCaller, + ::subxt::ext::subxt_core::utils::AccountId32, + ::core::primitive::u64, + >, + >, + >; + pub type Param0 = runtime_types::qp_scheduler::BlockNumberOrTimestamp< ::core::primitive::u32, ::core::primitive::u64, >; - pub type MaybePeriodic = ::core::option::Option<( + } + pub mod retries { + use super::runtime_types; + pub type Retries = runtime_types::pallet_scheduler::RetryConfig< + runtime_types::qp_scheduler::BlockNumberOrTimestamp< + ::core::primitive::u32, + ::core::primitive::u64, + >, + >; + pub type Param0 = ( runtime_types::qp_scheduler::BlockNumberOrTimestamp< ::core::primitive::u32, ::core::primitive::u64, >, ::core::primitive::u32, - )>; - pub type Priority = ::core::primitive::u8; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ScheduleNamedAfter { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "schedule_named_after"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Set a retry configuration for a task so that, in case its scheduled run fails, it will"] - #[doc = "be retried after `period` blocks, for a total amount of `retries` retries or until it"] - #[doc = "succeeds."] - #[doc = ""] - #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] - #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] - #[doc = "clones of the original task. Their retry configuration will be derived from the"] - #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] - #[doc = "original `total_retries`."] - pub struct SetRetry { - pub task: set_retry::Task, - pub retries: set_retry::Retries, - pub period: set_retry::Period, + ); } - pub mod set_retry { + pub mod lookup { use super::runtime_types; - pub type Task = ( + pub type Lookup = ( runtime_types::qp_scheduler::BlockNumberOrTimestamp< ::core::primitive::u32, ::core::primitive::u64, >, ::core::primitive::u32, ); - pub type Retries = ::core::primitive::u8; - pub type Period = runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >; + pub type Param0 = [::core::primitive::u8; 32usize]; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SetRetry { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "set_retry"; + } + pub struct StorageApi; + impl StorageApi { + #[doc = " Tracks incomplete block-based agendas that need to be processed in a later block."] + pub fn incomplete_block_since( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::incomplete_block_since::IncompleteBlockSince, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Scheduler", + "IncompleteBlockSince", + (), + [ + 134u8, 34u8, 161u8, 236u8, 176u8, 35u8, 218u8, 109u8, 229u8, 93u8, + 29u8, 95u8, 81u8, 106u8, 98u8, 65u8, 132u8, 91u8, 237u8, 225u8, 75u8, + 125u8, 81u8, 218u8, 72u8, 215u8, 20u8, 66u8, 160u8, 196u8, 68u8, 34u8, + ], + ) } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Set a retry configuration for a named task so that, in case its scheduled run fails, it"] - #[doc = "will be retried after `period` blocks, for a total amount of `retries` retries or until"] - #[doc = "it succeeds."] - #[doc = ""] - #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] - #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] - #[doc = "clones of the original task. Their retry configuration will be derived from the"] - #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] - #[doc = "original `total_retries`."] - pub struct SetRetryNamed { - pub id: set_retry_named::Id, - pub retries: set_retry_named::Retries, - pub period: set_retry_named::Period, - } - pub mod set_retry_named { - use super::runtime_types; - pub type Id = [::core::primitive::u8; 32usize]; - pub type Retries = ::core::primitive::u8; - pub type Period = runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SetRetryNamed { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "set_retry_named"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Removes the retry configuration of a task."] - pub struct CancelRetry { - pub task: cancel_retry::Task, - } - pub mod cancel_retry { - use super::runtime_types; - pub type Task = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CancelRetry { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "cancel_retry"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Cancel the retry configuration of a named task."] - pub struct CancelRetryNamed { - pub id: cancel_retry_named::Id, - } - pub mod cancel_retry_named { - use super::runtime_types; - pub type Id = [::core::primitive::u8; 32usize]; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CancelRetryNamed { - const PALLET: &'static str = "Scheduler"; - const CALL: &'static str = "cancel_retry_named"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "Anonymously schedule a task."] - pub fn schedule( + #[doc = " Tracks incomplete timestamp-based agendas that need to be processed in a later block."] + pub fn incomplete_timestamp_since( &self, - when: types::schedule::When, - maybe_periodic: types::schedule::MaybePeriodic, - priority: types::schedule::Priority, - call: types::schedule::Call, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::incomplete_timestamp_since::IncompleteTimestampSince, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "Scheduler", - "schedule", - types::Schedule { - when, - maybe_periodic, - priority, - call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), - }, + "IncompleteTimestampSince", + (), [ - 98u8, 56u8, 162u8, 148u8, 112u8, 249u8, 195u8, 138u8, 14u8, 208u8, - 216u8, 29u8, 136u8, 77u8, 22u8, 170u8, 181u8, 92u8, 215u8, 105u8, - 123u8, 64u8, 0u8, 48u8, 135u8, 65u8, 103u8, 121u8, 222u8, 161u8, 220u8, - 252u8, + 223u8, 125u8, 99u8, 28u8, 81u8, 135u8, 125u8, 26u8, 3u8, 20u8, 32u8, + 125u8, 141u8, 114u8, 100u8, 38u8, 219u8, 191u8, 30u8, 88u8, 82u8, 33u8, + 140u8, 223u8, 168u8, 84u8, 144u8, 85u8, 57u8, 241u8, 97u8, 141u8, ], ) } - #[doc = "Cancel an anonymously scheduled task."] - pub fn cancel( + #[doc = " Tracks the last timestamp bucket that was fully processed."] + #[doc = " Used to avoid reprocessing all buckets from 0 on every run."] + pub fn last_processed_timestamp( &self, - when: types::cancel::When, - index: types::cancel::Index, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::last_processed_timestamp::LastProcessedTimestamp, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "Scheduler", - "cancel", - types::Cancel { when, index }, + "LastProcessedTimestamp", + (), [ - 134u8, 77u8, 15u8, 56u8, 137u8, 12u8, 58u8, 147u8, 164u8, 204u8, 221u8, - 150u8, 103u8, 42u8, 36u8, 79u8, 146u8, 115u8, 13u8, 194u8, 39u8, 73u8, - 109u8, 10u8, 168u8, 164u8, 190u8, 173u8, 30u8, 17u8, 35u8, 17u8, + 172u8, 193u8, 6u8, 47u8, 185u8, 134u8, 179u8, 132u8, 178u8, 0u8, 228u8, + 198u8, 232u8, 24u8, 85u8, 199u8, 102u8, 222u8, 246u8, 178u8, 8u8, + 221u8, 51u8, 188u8, 239u8, 218u8, 112u8, 245u8, 46u8, 146u8, 65u8, + 119u8, ], ) } - #[doc = "Schedule a named task."] - pub fn schedule_named( + #[doc = " Items to be executed, indexed by the block number that they should be executed on."] + pub fn agenda_iter( &self, - id: types::schedule_named::Id, - when: types::schedule_named::When, - maybe_periodic: types::schedule_named::MaybePeriodic, - priority: types::schedule_named::Priority, - call: types::schedule_named::Call, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::agenda::Agenda, + (), + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "Scheduler", - "schedule_named", - types::ScheduleNamed { - id, - when, - maybe_periodic, - priority, - call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), - }, + "Agenda", + (), [ - 199u8, 176u8, 11u8, 253u8, 206u8, 181u8, 22u8, 109u8, 121u8, 2u8, - 189u8, 149u8, 188u8, 210u8, 81u8, 219u8, 147u8, 140u8, 252u8, 149u8, - 128u8, 248u8, 171u8, 106u8, 7u8, 152u8, 32u8, 65u8, 61u8, 121u8, 175u8, - 153u8, + 188u8, 177u8, 84u8, 167u8, 206u8, 4u8, 136u8, 133u8, 67u8, 121u8, + 247u8, 186u8, 6u8, 46u8, 115u8, 104u8, 239u8, 41u8, 75u8, 143u8, 24u8, + 155u8, 212u8, 196u8, 166u8, 82u8, 63u8, 39u8, 104u8, 21u8, 19u8, 93u8, ], ) } - #[doc = "Cancel a named scheduled task."] - pub fn cancel_named( + #[doc = " Items to be executed, indexed by the block number that they should be executed on."] + pub fn agenda( &self, - id: types::cancel_named::Id, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + _0: types::agenda::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::agenda::Param0, + >, + types::agenda::Agenda, + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "Scheduler", - "cancel_named", - types::CancelNamed { id }, + "Agenda", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 205u8, 35u8, 28u8, 57u8, 224u8, 7u8, 49u8, 233u8, 236u8, 163u8, 93u8, - 236u8, 103u8, 69u8, 65u8, 51u8, 121u8, 84u8, 9u8, 196u8, 147u8, 122u8, - 227u8, 200u8, 181u8, 233u8, 62u8, 240u8, 174u8, 83u8, 129u8, 193u8, + 188u8, 177u8, 84u8, 167u8, 206u8, 4u8, 136u8, 133u8, 67u8, 121u8, + 247u8, 186u8, 6u8, 46u8, 115u8, 104u8, 239u8, 41u8, 75u8, 143u8, 24u8, + 155u8, 212u8, 196u8, 166u8, 82u8, 63u8, 39u8, 104u8, 21u8, 19u8, 93u8, ], ) } - #[doc = "Anonymously schedule a task after a delay."] - pub fn schedule_after( + #[doc = " Retry configurations for items to be executed, indexed by task address."] + pub fn retries_iter( &self, - after: types::schedule_after::After, - maybe_periodic: types::schedule_after::MaybePeriodic, - priority: types::schedule_after::Priority, - call: types::schedule_after::Call, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::retries::Retries, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "Scheduler", - "schedule_after", - types::ScheduleAfter { - after, - maybe_periodic, - priority, - call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), - }, + "Retries", + (), [ - 241u8, 149u8, 155u8, 185u8, 58u8, 107u8, 11u8, 188u8, 177u8, 36u8, - 106u8, 40u8, 178u8, 137u8, 85u8, 190u8, 46u8, 56u8, 244u8, 20u8, 150u8, - 238u8, 73u8, 111u8, 151u8, 150u8, 2u8, 133u8, 218u8, 189u8, 95u8, - 109u8, + 94u8, 54u8, 136u8, 189u8, 244u8, 118u8, 102u8, 67u8, 203u8, 238u8, + 109u8, 130u8, 229u8, 246u8, 244u8, 68u8, 59u8, 132u8, 12u8, 9u8, 219u8, + 176u8, 251u8, 1u8, 216u8, 200u8, 205u8, 176u8, 145u8, 201u8, 206u8, + 108u8, ], ) } - #[doc = "Schedule a named task after a delay."] - pub fn schedule_named_after( + #[doc = " Retry configurations for items to be executed, indexed by task address."] + pub fn retries( &self, - id: types::schedule_named_after::Id, - after: types::schedule_named_after::After, - maybe_periodic: types::schedule_named_after::MaybePeriodic, - priority: types::schedule_named_after::Priority, - call: types::schedule_named_after::Call, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + _0: types::retries::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::retries::Param0, + >, + types::retries::Retries, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "Scheduler", - "schedule_named_after", - types::ScheduleNamedAfter { - id, - after, - maybe_periodic, - priority, - call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), - }, + "Retries", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 130u8, 87u8, 248u8, 189u8, 84u8, 139u8, 26u8, 139u8, 35u8, 18u8, 102u8, - 95u8, 127u8, 218u8, 144u8, 149u8, 65u8, 134u8, 86u8, 98u8, 195u8, - 192u8, 79u8, 154u8, 7u8, 232u8, 76u8, 179u8, 255u8, 188u8, 29u8, 191u8, - ], - ) + 94u8, 54u8, 136u8, 189u8, 244u8, 118u8, 102u8, 67u8, 203u8, 238u8, + 109u8, 130u8, 229u8, 246u8, 244u8, 68u8, 59u8, 132u8, 12u8, 9u8, 219u8, + 176u8, 251u8, 1u8, 216u8, 200u8, 205u8, 176u8, 145u8, 201u8, 206u8, + 108u8, + ], + ) } - #[doc = "Set a retry configuration for a task so that, in case its scheduled run fails, it will"] - #[doc = "be retried after `period` blocks, for a total amount of `retries` retries or until it"] - #[doc = "succeeds."] - #[doc = ""] - #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] + #[doc = " Lookup from a name to the block number and index of the task."] #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] - #[doc = "clones of the original task. Their retry configuration will be derived from the"] - #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] - #[doc = "original `total_retries`."] - pub fn set_retry( + #[doc = " For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4"] + #[doc = " identities."] + pub fn lookup_iter( &self, - task: types::set_retry::Task, - retries: types::set_retry::Retries, - period: types::set_retry::Period, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::lookup::Lookup, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "Scheduler", - "set_retry", - types::SetRetry { task, retries, period }, + "Lookup", + (), [ - 31u8, 128u8, 255u8, 13u8, 13u8, 252u8, 74u8, 151u8, 60u8, 242u8, 152u8, - 58u8, 190u8, 155u8, 132u8, 65u8, 139u8, 208u8, 222u8, 175u8, 89u8, - 222u8, 186u8, 98u8, 53u8, 125u8, 71u8, 55u8, 95u8, 2u8, 76u8, 248u8, + 133u8, 194u8, 6u8, 16u8, 27u8, 10u8, 159u8, 62u8, 113u8, 59u8, 58u8, + 225u8, 244u8, 206u8, 35u8, 113u8, 41u8, 40u8, 89u8, 71u8, 133u8, 117u8, + 33u8, 192u8, 106u8, 85u8, 83u8, 186u8, 36u8, 160u8, 144u8, 221u8, ], ) } - #[doc = "Set a retry configuration for a named task so that, in case its scheduled run fails, it"] - #[doc = "will be retried after `period` blocks, for a total amount of `retries` retries or until"] - #[doc = "it succeeds."] - #[doc = ""] - #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] + #[doc = " Lookup from a name to the block number and index of the task."] #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] - #[doc = "clones of the original task. Their retry configuration will be derived from the"] - #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] - #[doc = "original `total_retries`."] - pub fn set_retry_named( + #[doc = " For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4"] + #[doc = " identities."] + pub fn lookup( &self, - id: types::set_retry_named::Id, - retries: types::set_retry_named::Retries, - period: types::set_retry_named::Period, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + _0: types::lookup::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::lookup::Param0, + >, + types::lookup::Lookup, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "Scheduler", - "set_retry_named", - types::SetRetryNamed { id, retries, period }, + "Lookup", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 102u8, 70u8, 114u8, 48u8, 180u8, 194u8, 107u8, 81u8, 104u8, 117u8, - 33u8, 169u8, 43u8, 172u8, 61u8, 129u8, 143u8, 221u8, 44u8, 101u8, - 235u8, 228u8, 224u8, 71u8, 65u8, 223u8, 180u8, 130u8, 83u8, 89u8, - 157u8, 75u8, + 133u8, 194u8, 6u8, 16u8, 27u8, 10u8, 159u8, 62u8, 113u8, 59u8, 58u8, + 225u8, 244u8, 206u8, 35u8, 113u8, 41u8, 40u8, 89u8, 71u8, 133u8, 117u8, + 33u8, 192u8, 106u8, 85u8, 83u8, 186u8, 36u8, 160u8, 144u8, 221u8, ], ) } - #[doc = "Removes the retry configuration of a task."] - pub fn cancel_retry( + } + } + pub mod constants { + use super::runtime_types; + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " The maximum weight that may be scheduled per block for any dispatchables."] + pub fn maximum_weight( &self, - task: types::cancel_retry::Task, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + runtime_types::sp_weights::weight_v2::Weight, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( "Scheduler", - "cancel_retry", - types::CancelRetry { task }, + "MaximumWeight", [ - 153u8, 252u8, 168u8, 142u8, 100u8, 114u8, 25u8, 46u8, 225u8, 95u8, - 243u8, 78u8, 160u8, 175u8, 17u8, 33u8, 27u8, 241u8, 149u8, 187u8, - 228u8, 182u8, 233u8, 74u8, 10u8, 228u8, 117u8, 218u8, 210u8, 127u8, - 245u8, 105u8, + 149u8, 252u8, 129u8, 80u8, 169u8, 36u8, 79u8, 127u8, 240u8, 156u8, + 56u8, 202u8, 219u8, 86u8, 5u8, 65u8, 245u8, 148u8, 138u8, 243u8, 210u8, + 128u8, 234u8, 216u8, 240u8, 219u8, 123u8, 235u8, 21u8, 158u8, 237u8, + 112u8, ], ) } - #[doc = "Cancel the retry configuration of a named task."] - pub fn cancel_retry_named( + #[doc = " The maximum number of scheduled calls in the queue for a single block."] + #[doc = ""] + #[doc = " NOTE:"] + #[doc = " + Dependent pallets' benchmarks might require a higher limit for the setting. Set a"] + #[doc = " higher limit under `runtime-benchmarks` feature."] + pub fn max_scheduled_per_block( &self, - id: types::cancel_retry_named::Id, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( "Scheduler", - "cancel_retry_named", - types::CancelRetryNamed { id }, + "MaxScheduledPerBlock", [ - 76u8, 157u8, 253u8, 113u8, 162u8, 54u8, 98u8, 21u8, 62u8, 44u8, 155u8, - 202u8, 2u8, 28u8, 153u8, 219u8, 67u8, 166u8, 206u8, 79u8, 139u8, 3u8, - 119u8, 182u8, 254u8, 134u8, 143u8, 121u8, 155u8, 220u8, 192u8, 209u8, + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, ], ) } - } - } - #[doc = "Events type."] - pub type Event = runtime_types::pallet_scheduler::pallet::Event; - pub mod events { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Scheduled some task."] - pub struct Scheduled { - pub when: scheduled::When, - pub index: scheduled::Index, - } - pub mod scheduled { - use super::runtime_types; - pub type When = runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >; - pub type Index = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Scheduled { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "Scheduled"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Canceled some task."] - pub struct Canceled { - pub when: canceled::When, - pub index: canceled::Index, - } - pub mod canceled { - use super::runtime_types; - pub type When = runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, + #[doc = " Precision of the timestamp buckets."] + #[doc = ""] + #[doc = " Timestamp based dispatches are rounded to the nearest bucket of this precision."] + pub fn timestamp_bucket_size( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< ::core::primitive::u64, - >; - pub type Index = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Canceled { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "Canceled"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Dispatched some task."] - pub struct Dispatched { - pub task: dispatched::Task, - pub id: dispatched::Id, - pub result: dispatched::Result, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Scheduler", + "TimestampBucketSize", + [ + 128u8, 214u8, 205u8, 242u8, 181u8, 142u8, 124u8, 231u8, 190u8, 146u8, + 59u8, 226u8, 157u8, 101u8, 103u8, 117u8, 249u8, 65u8, 18u8, 191u8, + 103u8, 119u8, 53u8, 85u8, 81u8, 96u8, 220u8, 42u8, 184u8, 239u8, 42u8, + 246u8, + ], + ) + } } - pub mod dispatched { + } + } + pub mod utility { + use super::{root_mod, runtime_types}; + #[doc = "The `Error` enum of this pallet."] + pub type Error = runtime_types::pallet_utility::pallet::Error; + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::pallet_utility::pallet::Call; + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + pub mod types { use super::runtime_types; - pub type Task = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; - pub type Result = - ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Dispatched { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "Dispatched"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Set a retry configuration for some task."] - pub struct RetrySet { - pub task: retry_set::Task, - pub id: retry_set::Id, - pub period: retry_set::Period, - pub retries: retry_set::Retries, - } - pub mod retry_set { - use super::runtime_types; - pub type Task = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; - pub type Period = runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >; - pub type Retries = ::core::primitive::u8; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for RetrySet { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "RetrySet"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Cancel a retry configuration for some task."] - pub struct RetryCancelled { - pub task: retry_cancelled::Task, - pub id: retry_cancelled::Id, - } - pub mod retry_cancelled { - use super::runtime_types; - pub type Task = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for RetryCancelled { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "RetryCancelled"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "The call for the provided hash was not found so the task has been aborted."] - pub struct CallUnavailable { - pub task: call_unavailable::Task, - pub id: call_unavailable::Id, - } - pub mod call_unavailable { - use super::runtime_types; - pub type Task = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for CallUnavailable { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "CallUnavailable"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "The given task was unable to be renewed since the agenda is full at that block."] - pub struct PeriodicFailed { - pub task: periodic_failed::Task, - pub id: periodic_failed::Id, - } - pub mod periodic_failed { - use super::runtime_types; - pub type Task = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for PeriodicFailed { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "PeriodicFailed"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "The given task was unable to be retried since the agenda is full at that block or there"] - #[doc = "was not enough weight to reschedule it."] - pub struct RetryFailed { - pub task: retry_failed::Task, - pub id: retry_failed::Id, - } - pub mod retry_failed { - use super::runtime_types; - pub type Task = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for RetryFailed { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "RetryFailed"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "The given task can never be executed since it is overweight."] - pub struct PermanentlyOverweight { - pub task: permanently_overweight::Task, - pub id: permanently_overweight::Id, - } - pub mod permanently_overweight { - use super::runtime_types; - pub type Task = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for PermanentlyOverweight { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "PermanentlyOverweight"; - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod incomplete_block_since { - use super::runtime_types; - pub type IncompleteBlockSince = ::core::primitive::u32; - } - pub mod incomplete_timestamp_since { - use super::runtime_types; - pub type IncompleteTimestampSince = ::core::primitive::u64; - } - pub mod last_processed_timestamp { - use super::runtime_types; - pub type LastProcessedTimestamp = ::core::primitive::u64; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Send a batch of dispatch calls."] + #[doc = ""] + #[doc = "May be called from any origin except `None`."] + #[doc = ""] + #[doc = "- `calls`: The calls to be dispatched from the same origin. The number of call must not"] + #[doc = " exceed the constant: `batched_calls_limit` (available in constant metadata)."] + #[doc = ""] + #[doc = "If origin is root then the calls are dispatched without checking origin filter. (This"] + #[doc = "includes bypassing `frame_system::Config::BaseCallFilter`)."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(C) where C is the number of calls to be batched."] + #[doc = ""] + #[doc = "This will return `Ok` in all circumstances. To determine the success of the batch, an"] + #[doc = "event is deposited. If a call failed and the batch was interrupted, then the"] + #[doc = "`BatchInterrupted` event is deposited, along with the number of successful calls made"] + #[doc = "and the error of the failed call. If all were successful, then the `BatchCompleted`"] + #[doc = "event is deposited."] + pub struct Batch { + pub calls: batch::Calls, } - pub mod agenda { + pub mod batch { use super::runtime_types; - pub type Agenda = runtime_types::bounded_collections::bounded_vec::BoundedVec< - ::core::option::Option< - runtime_types::pallet_scheduler::Scheduled< - [::core::primitive::u8; 32usize], - runtime_types::frame_support::traits::preimages::Bounded< - runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, - >, - ::core::primitive::u32, - runtime_types::quantus_runtime::OriginCaller, - ::subxt::ext::subxt_core::utils::AccountId32, - ::core::primitive::u64, - >, - >, - >; - pub type Param0 = runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, + pub type Calls = ::subxt::ext::subxt_core::alloc::vec::Vec< + runtime_types::quantus_runtime::RuntimeCall, >; } - pub mod retries { - use super::runtime_types; - pub type Retries = runtime_types::pallet_scheduler::RetryConfig< - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - >; - pub type Param0 = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Batch { + const PALLET: &'static str = "Utility"; + const CALL: &'static str = "batch"; } - pub mod lookup { - use super::runtime_types; - pub type Lookup = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - pub type Param0 = [::core::primitive::u8; 32usize]; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Send a call through an indexed pseudonym of the sender."] + #[doc = ""] + #[doc = "Filter from origin are passed along. The call will be dispatched with an origin which"] + #[doc = "use the same filter as the origin of this call."] + #[doc = ""] + #[doc = "NOTE: If you need to ensure that any account-based filtering is not honored (i.e."] + #[doc = "because you expect `proxy` to have been used prior in the call stack and you do not want"] + #[doc = "the call restrictions to apply to any sub-accounts), then use `as_multi_threshold_1`"] + #[doc = "in the Multisig pallet instead."] + #[doc = ""] + #[doc = "NOTE: Prior to version *12, this was called `as_limited_sub`."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + pub struct AsDerivative { + pub index: as_derivative::Index, + pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, } - } - pub struct StorageApi; - impl StorageApi { - #[doc = " Tracks incomplete block-based agendas that need to be processed in a later block."] - pub fn incomplete_block_since( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::incomplete_block_since::IncompleteBlockSince, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Scheduler", - "IncompleteBlockSince", - (), - [ - 134u8, 34u8, 161u8, 236u8, 176u8, 35u8, 218u8, 109u8, 229u8, 93u8, - 29u8, 95u8, 81u8, 106u8, 98u8, 65u8, 132u8, 91u8, 237u8, 225u8, 75u8, - 125u8, 81u8, 218u8, 72u8, 215u8, 20u8, 66u8, 160u8, 196u8, 68u8, 34u8, - ], - ) + pub mod as_derivative { + use super::runtime_types; + pub type Index = ::core::primitive::u16; + pub type Call = runtime_types::quantus_runtime::RuntimeCall; } - #[doc = " Tracks incomplete timestamp-based agendas that need to be processed in a later block."] - pub fn incomplete_timestamp_since( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::incomplete_timestamp_since::IncompleteTimestampSince, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Scheduler", - "IncompleteTimestampSince", - (), - [ - 223u8, 125u8, 99u8, 28u8, 81u8, 135u8, 125u8, 26u8, 3u8, 20u8, 32u8, - 125u8, 141u8, 114u8, 100u8, 38u8, 219u8, 191u8, 30u8, 88u8, 82u8, 33u8, - 140u8, 223u8, 168u8, 84u8, 144u8, 85u8, 57u8, 241u8, 97u8, 141u8, - ], - ) + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for AsDerivative { + const PALLET: &'static str = "Utility"; + const CALL: &'static str = "as_derivative"; } - #[doc = " Tracks the last timestamp bucket that was fully processed."] - #[doc = " Used to avoid reprocessing all buckets from 0 on every run."] - pub fn last_processed_timestamp( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::last_processed_timestamp::LastProcessedTimestamp, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Scheduler", - "LastProcessedTimestamp", - (), - [ - 172u8, 193u8, 6u8, 47u8, 185u8, 134u8, 179u8, 132u8, 178u8, 0u8, 228u8, - 198u8, 232u8, 24u8, 85u8, 199u8, 102u8, 222u8, 246u8, 178u8, 8u8, - 221u8, 51u8, 188u8, 239u8, 218u8, 112u8, 245u8, 46u8, 146u8, 65u8, - 119u8, - ], - ) + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Send a batch of dispatch calls and atomically execute them."] + #[doc = "The whole transaction will rollback and fail if any of the calls failed."] + #[doc = ""] + #[doc = "May be called from any origin except `None`."] + #[doc = ""] + #[doc = "- `calls`: The calls to be dispatched from the same origin. The number of call must not"] + #[doc = " exceed the constant: `batched_calls_limit` (available in constant metadata)."] + #[doc = ""] + #[doc = "If origin is root then the calls are dispatched without checking origin filter. (This"] + #[doc = "includes bypassing `frame_system::Config::BaseCallFilter`)."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(C) where C is the number of calls to be batched."] + pub struct BatchAll { + pub calls: batch_all::Calls, } - #[doc = " Items to be executed, indexed by the block number that they should be executed on."] - pub fn agenda_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::agenda::Agenda, - (), - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Scheduler", - "Agenda", - (), - [ - 188u8, 177u8, 84u8, 167u8, 206u8, 4u8, 136u8, 133u8, 67u8, 121u8, - 247u8, 186u8, 6u8, 46u8, 115u8, 104u8, 239u8, 41u8, 75u8, 143u8, 24u8, - 155u8, 212u8, 196u8, 166u8, 82u8, 63u8, 39u8, 104u8, 21u8, 19u8, 93u8, - ], - ) + pub mod batch_all { + use super::runtime_types; + pub type Calls = ::subxt::ext::subxt_core::alloc::vec::Vec< + runtime_types::quantus_runtime::RuntimeCall, + >; } - #[doc = " Items to be executed, indexed by the block number that they should be executed on."] - pub fn agenda( - &self, - _0: types::agenda::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::agenda::Param0, - >, - types::agenda::Agenda, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Scheduler", - "Agenda", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 188u8, 177u8, 84u8, 167u8, 206u8, 4u8, 136u8, 133u8, 67u8, 121u8, - 247u8, 186u8, 6u8, 46u8, 115u8, 104u8, 239u8, 41u8, 75u8, 143u8, 24u8, - 155u8, 212u8, 196u8, 166u8, 82u8, 63u8, 39u8, 104u8, 21u8, 19u8, 93u8, - ], - ) + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for BatchAll { + const PALLET: &'static str = "Utility"; + const CALL: &'static str = "batch_all"; } - #[doc = " Retry configurations for items to be executed, indexed by task address."] - pub fn retries_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::retries::Retries, - (), - (), - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Scheduler", - "Retries", - (), - [ - 94u8, 54u8, 136u8, 189u8, 244u8, 118u8, 102u8, 67u8, 203u8, 238u8, - 109u8, 130u8, 229u8, 246u8, 244u8, 68u8, 59u8, 132u8, 12u8, 9u8, 219u8, - 176u8, 251u8, 1u8, 216u8, 200u8, 205u8, 176u8, 145u8, 201u8, 206u8, - 108u8, - ], - ) + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Dispatches a function call with a provided origin."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Root_."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(1)."] + pub struct DispatchAs { + pub as_origin: + ::subxt::ext::subxt_core::alloc::boxed::Box, + pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, } - #[doc = " Retry configurations for items to be executed, indexed by task address."] - pub fn retries( - &self, - _0: types::retries::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::retries::Param0, - >, - types::retries::Retries, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Scheduler", - "Retries", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 94u8, 54u8, 136u8, 189u8, 244u8, 118u8, 102u8, 67u8, 203u8, 238u8, - 109u8, 130u8, 229u8, 246u8, 244u8, 68u8, 59u8, 132u8, 12u8, 9u8, 219u8, - 176u8, 251u8, 1u8, 216u8, 200u8, 205u8, 176u8, 145u8, 201u8, 206u8, - 108u8, - ], - ) + pub mod dispatch_as { + use super::runtime_types; + pub type AsOrigin = runtime_types::quantus_runtime::OriginCaller; + pub type Call = runtime_types::quantus_runtime::RuntimeCall; } - #[doc = " Lookup from a name to the block number and index of the task."] - #[doc = ""] - #[doc = " For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4"] - #[doc = " identities."] - pub fn lookup_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::lookup::Lookup, - (), - (), - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Scheduler", - "Lookup", - (), - [ - 133u8, 194u8, 6u8, 16u8, 27u8, 10u8, 159u8, 62u8, 113u8, 59u8, 58u8, - 225u8, 244u8, 206u8, 35u8, 113u8, 41u8, 40u8, 89u8, 71u8, 133u8, 117u8, - 33u8, 192u8, 106u8, 85u8, 83u8, 186u8, 36u8, 160u8, 144u8, 221u8, - ], - ) - } - #[doc = " Lookup from a name to the block number and index of the task."] - #[doc = ""] - #[doc = " For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4"] - #[doc = " identities."] - pub fn lookup( - &self, - _0: types::lookup::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::lookup::Param0, - >, - types::lookup::Lookup, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Scheduler", - "Lookup", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 133u8, 194u8, 6u8, 16u8, 27u8, 10u8, 159u8, 62u8, 113u8, 59u8, 58u8, - 225u8, 244u8, 206u8, 35u8, 113u8, 41u8, 40u8, 89u8, 71u8, 133u8, 117u8, - 33u8, 192u8, 106u8, 85u8, 83u8, 186u8, 36u8, 160u8, 144u8, 221u8, - ], - ) - } - } - } - pub mod constants { - use super::runtime_types; - pub struct ConstantsApi; - impl ConstantsApi { - #[doc = " The maximum weight that may be scheduled per block for any dispatchables."] - pub fn maximum_weight( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - runtime_types::sp_weights::weight_v2::Weight, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Scheduler", - "MaximumWeight", - [ - 149u8, 252u8, 129u8, 80u8, 169u8, 36u8, 79u8, 127u8, 240u8, 156u8, - 56u8, 202u8, 219u8, 86u8, 5u8, 65u8, 245u8, 148u8, 138u8, 243u8, 210u8, - 128u8, 234u8, 216u8, 240u8, 219u8, 123u8, 235u8, 21u8, 158u8, 237u8, - 112u8, - ], - ) - } - #[doc = " The maximum number of scheduled calls in the queue for a single block."] - #[doc = ""] - #[doc = " NOTE:"] - #[doc = " + Dependent pallets' benchmarks might require a higher limit for the setting. Set a"] - #[doc = " higher limit under `runtime-benchmarks` feature."] - pub fn max_scheduled_per_block( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u32, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Scheduler", - "MaxScheduledPerBlock", - [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, - ], - ) - } - #[doc = " Precision of the timestamp buckets."] - #[doc = ""] - #[doc = " Timestamp based dispatches are rounded to the nearest bucket of this precision."] - pub fn timestamp_bucket_size( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u64, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Scheduler", - "TimestampBucketSize", - [ - 128u8, 214u8, 205u8, 242u8, 181u8, 142u8, 124u8, 231u8, 190u8, 146u8, - 59u8, 226u8, 157u8, 101u8, 103u8, 117u8, 249u8, 65u8, 18u8, 191u8, - 103u8, 119u8, 53u8, 85u8, 81u8, 96u8, 220u8, 42u8, 184u8, 239u8, 42u8, - 246u8, - ], - ) + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for DispatchAs { + const PALLET: &'static str = "Utility"; + const CALL: &'static str = "dispatch_as"; } - } - } - } - pub mod utility { - use super::{root_mod, runtime_types}; - #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_utility::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_utility::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, @@ -8372,35 +7916,30 @@ pub mod api { crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] #[doc = "Send a batch of dispatch calls."] + #[doc = "Unlike `batch`, it allows errors and won't interrupt."] #[doc = ""] #[doc = "May be called from any origin except `None`."] #[doc = ""] #[doc = "- `calls`: The calls to be dispatched from the same origin. The number of call must not"] #[doc = " exceed the constant: `batched_calls_limit` (available in constant metadata)."] #[doc = ""] - #[doc = "If origin is root then the calls are dispatched without checking origin filter. (This"] + #[doc = "If origin is root then the calls are dispatch without checking origin filter. (This"] #[doc = "includes bypassing `frame_system::Config::BaseCallFilter`)."] #[doc = ""] #[doc = "## Complexity"] #[doc = "- O(C) where C is the number of calls to be batched."] - #[doc = ""] - #[doc = "This will return `Ok` in all circumstances. To determine the success of the batch, an"] - #[doc = "event is deposited. If a call failed and the batch was interrupted, then the"] - #[doc = "`BatchInterrupted` event is deposited, along with the number of successful calls made"] - #[doc = "and the error of the failed call. If all were successful, then the `BatchCompleted`"] - #[doc = "event is deposited."] - pub struct Batch { - pub calls: batch::Calls, + pub struct ForceBatch { + pub calls: force_batch::Calls, } - pub mod batch { + pub mod force_batch { use super::runtime_types; pub type Calls = ::subxt::ext::subxt_core::alloc::vec::Vec< runtime_types::quantus_runtime::RuntimeCall, >; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Batch { + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ForceBatch { const PALLET: &'static str = "Utility"; - const CALL: &'static str = "batch"; + const CALL: &'static str = "force_batch"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -8413,31 +7952,24 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Send a call through an indexed pseudonym of the sender."] - #[doc = ""] - #[doc = "Filter from origin are passed along. The call will be dispatched with an origin which"] - #[doc = "use the same filter as the origin of this call."] - #[doc = ""] - #[doc = "NOTE: If you need to ensure that any account-based filtering is not honored (i.e."] - #[doc = "because you expect `proxy` to have been used prior in the call stack and you do not want"] - #[doc = "the call restrictions to apply to any sub-accounts), then use `as_multi_threshold_1`"] - #[doc = "in the Multisig pallet instead."] + #[doc = "Dispatch a function call with a specified weight."] #[doc = ""] - #[doc = "NOTE: Prior to version *12, this was called `as_limited_sub`."] + #[doc = "This function does not check the weight of the call, and instead allows the"] + #[doc = "Root origin to specify the weight of the call."] #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - pub struct AsDerivative { - pub index: as_derivative::Index, - pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, + #[doc = "The dispatch origin for this call must be _Root_."] + pub struct WithWeight { + pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, + pub weight: with_weight::Weight, } - pub mod as_derivative { + pub mod with_weight { use super::runtime_types; - pub type Index = ::core::primitive::u16; pub type Call = runtime_types::quantus_runtime::RuntimeCall; + pub type Weight = runtime_types::sp_weights::weight_v2::Weight; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for AsDerivative { + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for WithWeight { const PALLET: &'static str = "Utility"; - const CALL: &'static str = "as_derivative"; + const CALL: &'static str = "with_weight"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -8450,31 +7982,41 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Send a batch of dispatch calls and atomically execute them."] - #[doc = "The whole transaction will rollback and fail if any of the calls failed."] - #[doc = ""] + #[doc = "Dispatch a fallback call in the event the main call fails to execute."] #[doc = "May be called from any origin except `None`."] #[doc = ""] - #[doc = "- `calls`: The calls to be dispatched from the same origin. The number of call must not"] - #[doc = " exceed the constant: `batched_calls_limit` (available in constant metadata)."] + #[doc = "This function first attempts to dispatch the `main` call."] + #[doc = "If the `main` call fails, the `fallback` is attemted."] + #[doc = "if the fallback is successfully dispatched, the weights of both calls"] + #[doc = "are accumulated and an event containing the main call error is deposited."] #[doc = ""] - #[doc = "If origin is root then the calls are dispatched without checking origin filter. (This"] - #[doc = "includes bypassing `frame_system::Config::BaseCallFilter`)."] + #[doc = "In the event of a fallback failure the whole call fails"] + #[doc = "with the weights returned."] #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- O(C) where C is the number of calls to be batched."] - pub struct BatchAll { - pub calls: batch_all::Calls, + #[doc = "- `main`: The main call to be dispatched. This is the primary action to execute."] + #[doc = "- `fallback`: The fallback call to be dispatched in case the `main` call fails."] + #[doc = ""] + #[doc = "## Dispatch Logic"] + #[doc = "- If the origin is `root`, both the main and fallback calls are executed without"] + #[doc = " applying any origin filters."] + #[doc = "- If the origin is not `root`, the origin filter is applied to both the `main` and"] + #[doc = " `fallback` calls."] + #[doc = ""] + #[doc = "## Use Case"] + #[doc = "- Some use cases might involve submitting a `batch` type call in either main, fallback"] + #[doc = " or both."] + pub struct IfElse { + pub main: ::subxt::ext::subxt_core::alloc::boxed::Box, + pub fallback: ::subxt::ext::subxt_core::alloc::boxed::Box, } - pub mod batch_all { + pub mod if_else { use super::runtime_types; - pub type Calls = ::subxt::ext::subxt_core::alloc::vec::Vec< - runtime_types::quantus_runtime::RuntimeCall, - >; + pub type Main = runtime_types::quantus_runtime::RuntimeCall; + pub type Fallback = runtime_types::quantus_runtime::RuntimeCall; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for BatchAll { + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for IfElse { const PALLET: &'static str = "Utility"; - const CALL: &'static str = "batch_all"; + const CALL: &'static str = "if_else"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -8489,180 +8031,35 @@ pub mod api { )] #[doc = "Dispatches a function call with a provided origin."] #[doc = ""] - #[doc = "The dispatch origin for this call must be _Root_."] + #[doc = "Almost the same as [`Pallet::dispatch_as`] but forwards any error of the inner call."] #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- O(1)."] - pub struct DispatchAs { + #[doc = "The dispatch origin for this call must be _Root_."] + pub struct DispatchAsFallible { pub as_origin: - ::subxt::ext::subxt_core::alloc::boxed::Box, - pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, + ::subxt::ext::subxt_core::alloc::boxed::Box, + pub call: + ::subxt::ext::subxt_core::alloc::boxed::Box, } - pub mod dispatch_as { + pub mod dispatch_as_fallible { use super::runtime_types; pub type AsOrigin = runtime_types::quantus_runtime::OriginCaller; pub type Call = runtime_types::quantus_runtime::RuntimeCall; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for DispatchAs { + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for DispatchAsFallible { const PALLET: &'static str = "Utility"; - const CALL: &'static str = "dispatch_as"; + const CALL: &'static str = "dispatch_as_fallible"; } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] + } + pub struct TransactionApi; + impl TransactionApi { #[doc = "Send a batch of dispatch calls."] - #[doc = "Unlike `batch`, it allows errors and won't interrupt."] #[doc = ""] #[doc = "May be called from any origin except `None`."] #[doc = ""] #[doc = "- `calls`: The calls to be dispatched from the same origin. The number of call must not"] #[doc = " exceed the constant: `batched_calls_limit` (available in constant metadata)."] #[doc = ""] - #[doc = "If origin is root then the calls are dispatch without checking origin filter. (This"] - #[doc = "includes bypassing `frame_system::Config::BaseCallFilter`)."] - #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- O(C) where C is the number of calls to be batched."] - pub struct ForceBatch { - pub calls: force_batch::Calls, - } - pub mod force_batch { - use super::runtime_types; - pub type Calls = ::subxt::ext::subxt_core::alloc::vec::Vec< - runtime_types::quantus_runtime::RuntimeCall, - >; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ForceBatch { - const PALLET: &'static str = "Utility"; - const CALL: &'static str = "force_batch"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Dispatch a function call with a specified weight."] - #[doc = ""] - #[doc = "This function does not check the weight of the call, and instead allows the"] - #[doc = "Root origin to specify the weight of the call."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Root_."] - pub struct WithWeight { - pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, - pub weight: with_weight::Weight, - } - pub mod with_weight { - use super::runtime_types; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; - pub type Weight = runtime_types::sp_weights::weight_v2::Weight; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for WithWeight { - const PALLET: &'static str = "Utility"; - const CALL: &'static str = "with_weight"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Dispatch a fallback call in the event the main call fails to execute."] - #[doc = "May be called from any origin except `None`."] - #[doc = ""] - #[doc = "This function first attempts to dispatch the `main` call."] - #[doc = "If the `main` call fails, the `fallback` is attemted."] - #[doc = "if the fallback is successfully dispatched, the weights of both calls"] - #[doc = "are accumulated and an event containing the main call error is deposited."] - #[doc = ""] - #[doc = "In the event of a fallback failure the whole call fails"] - #[doc = "with the weights returned."] - #[doc = ""] - #[doc = "- `main`: The main call to be dispatched. This is the primary action to execute."] - #[doc = "- `fallback`: The fallback call to be dispatched in case the `main` call fails."] - #[doc = ""] - #[doc = "## Dispatch Logic"] - #[doc = "- If the origin is `root`, both the main and fallback calls are executed without"] - #[doc = " applying any origin filters."] - #[doc = "- If the origin is not `root`, the origin filter is applied to both the `main` and"] - #[doc = " `fallback` calls."] - #[doc = ""] - #[doc = "## Use Case"] - #[doc = "- Some use cases might involve submitting a `batch` type call in either main, fallback"] - #[doc = " or both."] - pub struct IfElse { - pub main: ::subxt::ext::subxt_core::alloc::boxed::Box, - pub fallback: ::subxt::ext::subxt_core::alloc::boxed::Box, - } - pub mod if_else { - use super::runtime_types; - pub type Main = runtime_types::quantus_runtime::RuntimeCall; - pub type Fallback = runtime_types::quantus_runtime::RuntimeCall; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for IfElse { - const PALLET: &'static str = "Utility"; - const CALL: &'static str = "if_else"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Dispatches a function call with a provided origin."] - #[doc = ""] - #[doc = "Almost the same as [`Pallet::dispatch_as`] but forwards any error of the inner call."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Root_."] - pub struct DispatchAsFallible { - pub as_origin: - ::subxt::ext::subxt_core::alloc::boxed::Box, - pub call: - ::subxt::ext::subxt_core::alloc::boxed::Box, - } - pub mod dispatch_as_fallible { - use super::runtime_types; - pub type AsOrigin = runtime_types::quantus_runtime::OriginCaller; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for DispatchAsFallible { - const PALLET: &'static str = "Utility"; - const CALL: &'static str = "dispatch_as_fallible"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "Send a batch of dispatch calls."] - #[doc = ""] - #[doc = "May be called from any origin except `None`."] - #[doc = ""] - #[doc = "- `calls`: The calls to be dispatched from the same origin. The number of call must not"] - #[doc = " exceed the constant: `batched_calls_limit` (available in constant metadata)."] - #[doc = ""] - #[doc = "If origin is root then the calls are dispatched without checking origin filter. (This"] + #[doc = "If origin is root then the calls are dispatched without checking origin filter. (This"] #[doc = "includes bypassing `frame_system::Config::BaseCallFilter`)."] #[doc = ""] #[doc = "## Complexity"] @@ -8682,9 +8079,10 @@ pub mod api { "batch", types::Batch { calls }, [ - 143u8, 230u8, 160u8, 33u8, 51u8, 78u8, 98u8, 70u8, 24u8, 252u8, 53u8, - 95u8, 142u8, 254u8, 85u8, 220u8, 208u8, 135u8, 35u8, 223u8, 159u8, 9u8, - 252u8, 220u8, 43u8, 167u8, 49u8, 44u8, 89u8, 178u8, 227u8, 192u8, + 111u8, 193u8, 119u8, 118u8, 37u8, 86u8, 134u8, 214u8, 148u8, 113u8, + 255u8, 207u8, 186u8, 6u8, 247u8, 84u8, 23u8, 246u8, 144u8, 242u8, + 114u8, 20u8, 105u8, 119u8, 137u8, 247u8, 189u8, 240u8, 237u8, 176u8, + 71u8, 249u8, ], ) } @@ -8714,10 +8112,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 214u8, 237u8, 32u8, 195u8, 191u8, 195u8, 55u8, 60u8, 99u8, 181u8, - 242u8, 109u8, 51u8, 83u8, 103u8, 100u8, 4u8, 196u8, 130u8, 130u8, - 190u8, 179u8, 224u8, 200u8, 67u8, 61u8, 214u8, 118u8, 5u8, 91u8, 104u8, - 72u8, + 50u8, 167u8, 42u8, 97u8, 124u8, 144u8, 249u8, 155u8, 195u8, 246u8, + 155u8, 91u8, 32u8, 182u8, 54u8, 42u8, 176u8, 178u8, 66u8, 99u8, 46u8, + 182u8, 8u8, 242u8, 233u8, 63u8, 68u8, 60u8, 204u8, 60u8, 49u8, 112u8, ], ) } @@ -8743,9 +8140,9 @@ pub mod api { "batch_all", types::BatchAll { calls }, [ - 181u8, 57u8, 166u8, 110u8, 27u8, 199u8, 129u8, 206u8, 52u8, 238u8, - 32u8, 165u8, 37u8, 48u8, 103u8, 144u8, 138u8, 34u8, 41u8, 94u8, 246u8, - 41u8, 110u8, 214u8, 14u8, 114u8, 86u8, 44u8, 95u8, 14u8, 201u8, 175u8, + 252u8, 233u8, 123u8, 196u8, 206u8, 108u8, 105u8, 36u8, 203u8, 174u8, + 73u8, 179u8, 76u8, 42u8, 56u8, 144u8, 167u8, 61u8, 204u8, 87u8, 132u8, + 57u8, 191u8, 199u8, 63u8, 71u8, 132u8, 174u8, 54u8, 230u8, 21u8, 199u8, ], ) } @@ -8768,9 +8165,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 10u8, 157u8, 57u8, 66u8, 109u8, 65u8, 72u8, 193u8, 5u8, 242u8, 129u8, - 169u8, 57u8, 0u8, 3u8, 210u8, 146u8, 49u8, 26u8, 109u8, 117u8, 2u8, - 189u8, 69u8, 186u8, 28u8, 163u8, 235u8, 225u8, 210u8, 111u8, 177u8, + 243u8, 223u8, 67u8, 77u8, 222u8, 227u8, 101u8, 159u8, 246u8, 109u8, + 238u8, 21u8, 135u8, 5u8, 26u8, 29u8, 49u8, 17u8, 29u8, 167u8, 76u8, + 84u8, 227u8, 151u8, 234u8, 214u8, 35u8, 234u8, 129u8, 163u8, 181u8, + 149u8, ], ) } @@ -8796,9 +8194,9 @@ pub mod api { "force_batch", types::ForceBatch { calls }, [ - 236u8, 54u8, 180u8, 85u8, 81u8, 119u8, 70u8, 224u8, 73u8, 103u8, 169u8, - 41u8, 191u8, 56u8, 138u8, 114u8, 255u8, 207u8, 13u8, 219u8, 217u8, - 35u8, 131u8, 51u8, 220u8, 168u8, 191u8, 5u8, 98u8, 225u8, 50u8, 137u8, + 13u8, 145u8, 1u8, 24u8, 146u8, 209u8, 200u8, 218u8, 24u8, 166u8, 190u8, + 203u8, 29u8, 162u8, 219u8, 181u8, 35u8, 237u8, 96u8, 196u8, 199u8, + 85u8, 173u8, 24u8, 184u8, 12u8, 148u8, 51u8, 14u8, 105u8, 131u8, 132u8, ], ) } @@ -8821,10 +8219,10 @@ pub mod api { weight, }, [ - 253u8, 207u8, 162u8, 133u8, 214u8, 66u8, 111u8, 171u8, 181u8, 86u8, - 82u8, 24u8, 121u8, 127u8, 80u8, 92u8, 21u8, 81u8, 255u8, 176u8, 61u8, - 95u8, 195u8, 109u8, 197u8, 42u8, 54u8, 204u8, 148u8, 107u8, 212u8, - 236u8, + 111u8, 148u8, 45u8, 217u8, 132u8, 185u8, 150u8, 232u8, 91u8, 77u8, + 142u8, 98u8, 175u8, 13u8, 252u8, 220u8, 199u8, 177u8, 171u8, 155u8, + 84u8, 242u8, 40u8, 132u8, 77u8, 201u8, 7u8, 25u8, 102u8, 169u8, 235u8, + 6u8, ], ) } @@ -8864,9 +8262,9 @@ pub mod api { fallback: ::subxt::ext::subxt_core::alloc::boxed::Box::new(fallback), }, [ - 251u8, 49u8, 108u8, 91u8, 215u8, 66u8, 153u8, 50u8, 76u8, 22u8, 82u8, - 115u8, 88u8, 37u8, 50u8, 69u8, 92u8, 225u8, 34u8, 143u8, 59u8, 13u8, - 222u8, 29u8, 130u8, 66u8, 25u8, 162u8, 78u8, 5u8, 113u8, 244u8, + 130u8, 245u8, 121u8, 31u8, 205u8, 1u8, 6u8, 43u8, 62u8, 146u8, 200u8, + 61u8, 223u8, 162u8, 42u8, 243u8, 202u8, 252u8, 66u8, 155u8, 227u8, + 70u8, 211u8, 133u8, 15u8, 65u8, 72u8, 47u8, 175u8, 127u8, 80u8, 88u8, ], ) } @@ -8889,9 +8287,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 20u8, 7u8, 177u8, 85u8, 1u8, 244u8, 203u8, 254u8, 2u8, 41u8, 209u8, - 209u8, 100u8, 23u8, 237u8, 67u8, 162u8, 62u8, 226u8, 220u8, 77u8, - 112u8, 238u8, 124u8, 247u8, 247u8, 153u8, 8u8, 19u8, 82u8, 84u8, 163u8, + 169u8, 9u8, 148u8, 133u8, 139u8, 233u8, 123u8, 12u8, 26u8, 40u8, 84u8, + 195u8, 239u8, 201u8, 104u8, 122u8, 9u8, 46u8, 249u8, 206u8, 220u8, + 186u8, 225u8, 142u8, 158u8, 10u8, 204u8, 24u8, 30u8, 246u8, 88u8, 15u8, ], ) } @@ -10541,6 +9939,32 @@ pub mod api { const PALLET: &'static str = "ReversibleTransfers"; const CALL: &'static str = "schedule_asset_transfer_with_delay"; } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Allows the guardian (interceptor) to recover all funds from a high security"] + #[doc = "account by transferring the entire balance to themselves."] + #[doc = ""] + #[doc = "This is an emergency function for when the high security account may be compromised."] + pub struct RecoverFunds { + pub account: recover_funds::Account, + } + pub mod recover_funds { + use super::runtime_types; + pub type Account = ::subxt::ext::subxt_core::utils::AccountId32; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for RecoverFunds { + const PALLET: &'static str = "ReversibleTransfers"; + const CALL: &'static str = "recover_funds"; + } } pub struct TransactionApi; impl TransactionApi { @@ -10700,6 +10124,26 @@ pub mod api { ], ) } + #[doc = "Allows the guardian (interceptor) to recover all funds from a high security"] + #[doc = "account by transferring the entire balance to themselves."] + #[doc = ""] + #[doc = "This is an emergency function for when the high security account may be compromised."] + pub fn recover_funds( + &self, + account: types::recover_funds::Account, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "ReversibleTransfers", + "recover_funds", + types::RecoverFunds { account }, + [ + 94u8, 241u8, 255u8, 110u8, 4u8, 169u8, 1u8, 45u8, 236u8, 88u8, 167u8, + 180u8, 240u8, 70u8, 111u8, 99u8, 185u8, 143u8, 153u8, 33u8, 101u8, + 30u8, 203u8, 103u8, 229u8, 39u8, 162u8, 76u8, 49u8, 125u8, 247u8, + 220u8, + ], + ) + } } } #[doc = "The `Event` enum of this pallet"] @@ -10776,7 +10220,6 @@ pub mod api { #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] #[doc = "A scheduled transaction has been successfully cancelled by the owner."] - #[doc = "[who, tx_id]"] pub struct TransactionCancelled { pub who: transaction_cancelled::Who, pub tx_id: transaction_cancelled::TxId, @@ -10798,7 +10241,6 @@ pub mod api { #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] #[doc = "A scheduled transaction was executed by the scheduler."] - #[doc = "[tx_id, dispatch_result]"] pub struct TransactionExecuted { pub tx_id: transaction_executed::TxId, pub result: transaction_executed::Result, @@ -10817,6 +10259,27 @@ pub mod api { const PALLET: &'static str = "ReversibleTransfers"; const EVENT: &'static str = "TransactionExecuted"; } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Funds were recovered from a high security account by its guardian."] + pub struct FundsRecovered { + pub account: funds_recovered::Account, + pub guardian: funds_recovered::Guardian, + } + pub mod funds_recovered { + use super::runtime_types; + pub type Account = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Guardian = ::subxt::ext::subxt_core::utils::AccountId32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for FundsRecovered { + const PALLET: &'static str = "ReversibleTransfers"; + const EVENT: &'static str = "FundsRecovered"; + } } pub mod storage { use super::runtime_types; @@ -11293,7 +10756,7 @@ pub mod api { } #[doc = " Volume fee taken from reversed transactions for high-security accounts only,"] #[doc = " expressed as a Permill (e.g., Permill::from_percent(1) = 1%). Regular accounts incur no"] - #[doc = " fees."] + #[doc = " fees. The fee is burned (removed from total issuance)."] pub fn volume_fee( &self, ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< @@ -14304,12 +13767,12 @@ pub mod api { } } } - pub mod merkle_airdrop { + pub mod treasury_pallet { use super::{root_mod, runtime_types}; - #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_merkle_airdrop::pallet::Error; + #[doc = "Error for the treasury pallet."] + pub type Error = runtime_types::pallet_treasury::pallet::Error; #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_merkle_airdrop::pallet::Call; + pub type Call = runtime_types::pallet_treasury::pallet::Call; pub mod calls { use super::{root_mod, runtime_types}; type DispatchError = runtime_types::sp_runtime::DispatchError; @@ -14326,70 +13789,39 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Create a new airdrop with a Merkle root."] - #[doc = ""] - #[doc = "The Merkle root is a cryptographic hash that represents all valid claims"] - #[doc = "for this airdrop. Users will later provide Merkle proofs to verify their"] - #[doc = "eligibility to claim tokens."] - #[doc = ""] - #[doc = "# Parameters"] + #[doc = "Propose and approve a spend of treasury funds."] #[doc = ""] - #[doc = "* `origin` - The origin of the call (must be signed)"] - #[doc = "* `merkle_root` - The Merkle root hash representing all valid claims"] - #[doc = "* `vesting_period` - Optional vesting period for the airdrop"] - #[doc = "* `vesting_delay` - Optional delay before vesting starts"] - pub struct CreateAirdrop { - pub merkle_root: create_airdrop::MerkleRoot, - pub vesting_period: create_airdrop::VestingPeriod, - pub vesting_delay: create_airdrop::VestingDelay, - } - pub mod create_airdrop { - use super::runtime_types; - pub type MerkleRoot = [::core::primitive::u8; 32usize]; - pub type VestingPeriod = ::core::option::Option<::core::primitive::u32>; - pub type VestingDelay = ::core::option::Option<::core::primitive::u32>; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CreateAirdrop { - const PALLET: &'static str = "MerkleAirdrop"; - const CALL: &'static str = "create_airdrop"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Fund an existing airdrop with tokens."] + #[doc = "## Dispatch Origin"] #[doc = ""] - #[doc = "This function transfers tokens from the caller to the airdrop's account,"] - #[doc = "making them available for users to claim."] + #[doc = "Must be [`Config::SpendOrigin`] with the `Success` value being at least `amount`."] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "### Details"] + #[doc = "NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the"] + #[doc = "beneficiary."] #[doc = ""] - #[doc = "* `origin` - The origin of the call (must be signed)"] - #[doc = "* `airdrop_id` - The ID of the airdrop to fund"] - #[doc = "* `amount` - The amount of tokens to add to the airdrop"] + #[doc = "### Parameters"] + #[doc = "- `amount`: The amount to be transferred from the treasury to the `beneficiary`."] + #[doc = "- `beneficiary`: The destination account for the transfer."] #[doc = ""] - #[doc = "# Errors"] + #[doc = "## Events"] #[doc = ""] - #[doc = "* `AirdropNotFound` - If the specified airdrop does not exist"] - pub struct FundAirdrop { - pub airdrop_id: fund_airdrop::AirdropId, - pub amount: fund_airdrop::Amount, + #[doc = "Emits [`Event::SpendApproved`] if successful."] + pub struct SpendLocal { + #[codec(compact)] + pub amount: spend_local::Amount, + pub beneficiary: spend_local::Beneficiary, } - pub mod fund_airdrop { + pub mod spend_local { use super::runtime_types; - pub type AirdropId = ::core::primitive::u32; pub type Amount = ::core::primitive::u128; + pub type Beneficiary = ::subxt::ext::subxt_core::utils::MultiAddress< + ::subxt::ext::subxt_core::utils::AccountId32, + (), + >; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for FundAirdrop { - const PALLET: &'static str = "MerkleAirdrop"; - const CALL: &'static str = "fund_airdrop"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SpendLocal { + const PALLET: &'static str = "TreasuryPallet"; + const CALL: &'static str = "spend_local"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -14402,44 +13834,38 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Claim tokens from an airdrop by providing a Merkle proof."] + #[doc = "Force a previously approved proposal to be removed from the approval queue."] + #[doc = ""] + #[doc = "## Dispatch Origin"] + #[doc = ""] + #[doc = "Must be [`Config::RejectOrigin`]."] #[doc = ""] - #[doc = "Users can claim their tokens by providing a proof of their eligibility."] - #[doc = "The proof is verified against the airdrop's Merkle root."] - #[doc = "Anyone can trigger a claim for any eligible recipient."] + #[doc = "## Details"] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "The original deposit will no longer be returned."] #[doc = ""] - #[doc = "* `origin` - The origin of the call"] - #[doc = "* `airdrop_id` - The ID of the airdrop to claim from"] - #[doc = "* `amount` - The amount of tokens to claim"] - #[doc = "* `merkle_proof` - The Merkle proof verifying eligibility"] + #[doc = "### Parameters"] + #[doc = "- `proposal_id`: The index of a proposal"] #[doc = ""] - #[doc = "# Errors"] + #[doc = "### Complexity"] + #[doc = "- O(A) where `A` is the number of approvals"] #[doc = ""] - #[doc = "* `AirdropNotFound` - If the specified airdrop does not exist"] - #[doc = "* `AlreadyClaimed` - If the recipient has already claimed from this airdrop"] - #[doc = "* `InvalidProof` - If the provided Merkle proof is invalid"] - #[doc = "* `InsufficientAirdropBalance` - If the airdrop doesn't have enough tokens"] - pub struct Claim { - pub airdrop_id: claim::AirdropId, - pub recipient: claim::Recipient, - pub amount: claim::Amount, - pub merkle_proof: claim::MerkleProof, + #[doc = "### Errors"] + #[doc = "- [`Error::ProposalNotApproved`]: The `proposal_id` supplied was not found in the"] + #[doc = " approval queue, i.e., the proposal has not been approved. This could also mean the"] + #[doc = " proposal does not exist altogether, thus there is no way it would have been approved"] + #[doc = " in the first place."] + pub struct RemoveApproval { + #[codec(compact)] + pub proposal_id: remove_approval::ProposalId, } - pub mod claim { + pub mod remove_approval { use super::runtime_types; - pub type AirdropId = ::core::primitive::u32; - pub type Recipient = ::subxt::ext::subxt_core::utils::AccountId32; - pub type Amount = ::core::primitive::u128; - pub type MerkleProof = - runtime_types::bounded_collections::bounded_vec::BoundedVec< - [::core::primitive::u8; 32usize], - >; + pub type ProposalId = ::core::primitive::u32; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Claim { - const PALLET: &'static str = "MerkleAirdrop"; - const CALL: &'static str = "claim"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for RemoveApproval { + const PALLET: &'static str = "TreasuryPallet"; + const CALL: &'static str = "remove_approval"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -14452,165 +13878,404 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Delete an airdrop and reclaim any remaining funds."] - #[doc = ""] - #[doc = "This function allows the creator of an airdrop to delete it and reclaim"] - #[doc = "any remaining tokens that haven't been claimed."] + #[doc = "Propose and approve a spend of treasury funds."] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "## Dispatch Origin"] #[doc = ""] - #[doc = "* `origin` - The origin of the call (must be the airdrop creator)"] - #[doc = "* `airdrop_id` - The ID of the airdrop to delete"] + #[doc = "Must be [`Config::SpendOrigin`] with the `Success` value being at least"] + #[doc = "`amount` of `asset_kind` in the native asset. The amount of `asset_kind` is converted"] + #[doc = "for assertion using the [`Config::BalanceConverter`]."] #[doc = ""] - #[doc = "# Errors"] + #[doc = "## Details"] #[doc = ""] - #[doc = "* `AirdropNotFound` - If the specified airdrop does not exist"] - #[doc = "* `NotAirdropCreator` - If the caller is not the creator of the airdrop"] - pub struct DeleteAirdrop { - pub airdrop_id: delete_airdrop::AirdropId, + #[doc = "Create an approved spend for transferring a specific `amount` of `asset_kind` to a"] + #[doc = "designated beneficiary. The spend must be claimed using the `payout` dispatchable within"] + #[doc = "the [`Config::PayoutPeriod`]."] + #[doc = ""] + #[doc = "### Parameters"] + #[doc = "- `asset_kind`: An indicator of the specific asset class to be spent."] + #[doc = "- `amount`: The amount to be transferred from the treasury to the `beneficiary`."] + #[doc = "- `beneficiary`: The beneficiary of the spend."] + #[doc = "- `valid_from`: The block number from which the spend can be claimed. It can refer to"] + #[doc = " the past if the resulting spend has not yet expired according to the"] + #[doc = " [`Config::PayoutPeriod`]. If `None`, the spend can be claimed immediately after"] + #[doc = " approval."] + #[doc = ""] + #[doc = "## Events"] + #[doc = ""] + #[doc = "Emits [`Event::AssetSpendApproved`] if successful."] + pub struct Spend { + pub asset_kind: ::subxt::ext::subxt_core::alloc::boxed::Box, + #[codec(compact)] + pub amount: spend::Amount, + pub beneficiary: + ::subxt::ext::subxt_core::alloc::boxed::Box, + pub valid_from: spend::ValidFrom, + } + pub mod spend { + use super::runtime_types; + pub type AssetKind = (); + pub type Amount = ::core::primitive::u128; + pub type Beneficiary = ::subxt::ext::subxt_core::utils::MultiAddress< + ::subxt::ext::subxt_core::utils::AccountId32, + (), + >; + pub type ValidFrom = ::core::option::Option<::core::primitive::u32>; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Spend { + const PALLET: &'static str = "TreasuryPallet"; + const CALL: &'static str = "spend"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Claim a spend."] + #[doc = ""] + #[doc = "## Dispatch Origin"] + #[doc = ""] + #[doc = "Must be signed"] + #[doc = ""] + #[doc = "## Details"] + #[doc = ""] + #[doc = "Spends must be claimed within some temporal bounds. A spend may be claimed within one"] + #[doc = "[`Config::PayoutPeriod`] from the `valid_from` block."] + #[doc = "In case of a payout failure, the spend status must be updated with the `check_status`"] + #[doc = "dispatchable before retrying with the current function."] + #[doc = ""] + #[doc = "### Parameters"] + #[doc = "- `index`: The spend index."] + #[doc = ""] + #[doc = "## Events"] + #[doc = ""] + #[doc = "Emits [`Event::Paid`] if successful."] + pub struct Payout { + pub index: payout::Index, + } + pub mod payout { + use super::runtime_types; + pub type Index = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Payout { + const PALLET: &'static str = "TreasuryPallet"; + const CALL: &'static str = "payout"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Check the status of the spend and remove it from the storage if processed."] + #[doc = ""] + #[doc = "## Dispatch Origin"] + #[doc = ""] + #[doc = "Must be signed."] + #[doc = ""] + #[doc = "## Details"] + #[doc = ""] + #[doc = "The status check is a prerequisite for retrying a failed payout."] + #[doc = "If a spend has either succeeded or expired, it is removed from the storage by this"] + #[doc = "function. In such instances, transaction fees are refunded."] + #[doc = ""] + #[doc = "### Parameters"] + #[doc = "- `index`: The spend index."] + #[doc = ""] + #[doc = "## Events"] + #[doc = ""] + #[doc = "Emits [`Event::PaymentFailed`] if the spend payout has failed."] + #[doc = "Emits [`Event::SpendProcessed`] if the spend payout has succeed."] + pub struct CheckStatus { + pub index: check_status::Index, + } + pub mod check_status { + use super::runtime_types; + pub type Index = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CheckStatus { + const PALLET: &'static str = "TreasuryPallet"; + const CALL: &'static str = "check_status"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Void previously approved spend."] + #[doc = ""] + #[doc = "## Dispatch Origin"] + #[doc = ""] + #[doc = "Must be [`Config::RejectOrigin`]."] + #[doc = ""] + #[doc = "## Details"] + #[doc = ""] + #[doc = "A spend void is only possible if the payout has not been attempted yet."] + #[doc = ""] + #[doc = "### Parameters"] + #[doc = "- `index`: The spend index."] + #[doc = ""] + #[doc = "## Events"] + #[doc = ""] + #[doc = "Emits [`Event::AssetSpendVoided`] if successful."] + pub struct VoidSpend { + pub index: void_spend::Index, } - pub mod delete_airdrop { + pub mod void_spend { use super::runtime_types; - pub type AirdropId = ::core::primitive::u32; + pub type Index = ::core::primitive::u32; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for DeleteAirdrop { - const PALLET: &'static str = "MerkleAirdrop"; - const CALL: &'static str = "delete_airdrop"; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for VoidSpend { + const PALLET: &'static str = "TreasuryPallet"; + const CALL: &'static str = "void_spend"; } } pub struct TransactionApi; impl TransactionApi { - #[doc = "Create a new airdrop with a Merkle root."] + #[doc = "Propose and approve a spend of treasury funds."] + #[doc = ""] + #[doc = "## Dispatch Origin"] + #[doc = ""] + #[doc = "Must be [`Config::SpendOrigin`] with the `Success` value being at least `amount`."] + #[doc = ""] + #[doc = "### Details"] + #[doc = "NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the"] + #[doc = "beneficiary."] #[doc = ""] - #[doc = "The Merkle root is a cryptographic hash that represents all valid claims"] - #[doc = "for this airdrop. Users will later provide Merkle proofs to verify their"] - #[doc = "eligibility to claim tokens."] + #[doc = "### Parameters"] + #[doc = "- `amount`: The amount to be transferred from the treasury to the `beneficiary`."] + #[doc = "- `beneficiary`: The destination account for the transfer."] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "## Events"] #[doc = ""] - #[doc = "* `origin` - The origin of the call (must be signed)"] - #[doc = "* `merkle_root` - The Merkle root hash representing all valid claims"] - #[doc = "* `vesting_period` - Optional vesting period for the airdrop"] - #[doc = "* `vesting_delay` - Optional delay before vesting starts"] - pub fn create_airdrop( + #[doc = "Emits [`Event::SpendApproved`] if successful."] + pub fn spend_local( &self, - merkle_root: types::create_airdrop::MerkleRoot, - vesting_period: types::create_airdrop::VestingPeriod, - vesting_delay: types::create_airdrop::VestingDelay, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { + amount: types::spend_local::Amount, + beneficiary: types::spend_local::Beneficiary, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "MerkleAirdrop", - "create_airdrop", - types::CreateAirdrop { merkle_root, vesting_period, vesting_delay }, + "TreasuryPallet", + "spend_local", + types::SpendLocal { amount, beneficiary }, [ - 18u8, 201u8, 105u8, 56u8, 66u8, 207u8, 57u8, 177u8, 133u8, 38u8, 185u8, - 19u8, 205u8, 119u8, 177u8, 206u8, 188u8, 88u8, 138u8, 33u8, 246u8, - 179u8, 148u8, 0u8, 79u8, 201u8, 89u8, 229u8, 46u8, 77u8, 42u8, 117u8, + 137u8, 171u8, 83u8, 247u8, 245u8, 212u8, 152u8, 127u8, 210u8, 71u8, + 254u8, 134u8, 189u8, 26u8, 249u8, 41u8, 214u8, 175u8, 24u8, 64u8, 33u8, + 90u8, 23u8, 134u8, 44u8, 110u8, 63u8, 46u8, 46u8, 146u8, 222u8, 79u8, ], ) } - #[doc = "Fund an existing airdrop with tokens."] + #[doc = "Force a previously approved proposal to be removed from the approval queue."] + #[doc = ""] + #[doc = "## Dispatch Origin"] + #[doc = ""] + #[doc = "Must be [`Config::RejectOrigin`]."] #[doc = ""] - #[doc = "This function transfers tokens from the caller to the airdrop's account,"] - #[doc = "making them available for users to claim."] + #[doc = "## Details"] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "The original deposit will no longer be returned."] #[doc = ""] - #[doc = "* `origin` - The origin of the call (must be signed)"] - #[doc = "* `airdrop_id` - The ID of the airdrop to fund"] - #[doc = "* `amount` - The amount of tokens to add to the airdrop"] + #[doc = "### Parameters"] + #[doc = "- `proposal_id`: The index of a proposal"] #[doc = ""] - #[doc = "# Errors"] + #[doc = "### Complexity"] + #[doc = "- O(A) where `A` is the number of approvals"] #[doc = ""] - #[doc = "* `AirdropNotFound` - If the specified airdrop does not exist"] - pub fn fund_airdrop( + #[doc = "### Errors"] + #[doc = "- [`Error::ProposalNotApproved`]: The `proposal_id` supplied was not found in the"] + #[doc = " approval queue, i.e., the proposal has not been approved. This could also mean the"] + #[doc = " proposal does not exist altogether, thus there is no way it would have been approved"] + #[doc = " in the first place."] + pub fn remove_approval( &self, - airdrop_id: types::fund_airdrop::AirdropId, - amount: types::fund_airdrop::Amount, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + proposal_id: types::remove_approval::ProposalId, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "MerkleAirdrop", - "fund_airdrop", - types::FundAirdrop { airdrop_id, amount }, + "TreasuryPallet", + "remove_approval", + types::RemoveApproval { proposal_id }, [ - 11u8, 155u8, 135u8, 152u8, 19u8, 196u8, 79u8, 68u8, 24u8, 46u8, 27u8, - 63u8, 202u8, 242u8, 166u8, 160u8, 81u8, 44u8, 115u8, 247u8, 110u8, - 49u8, 11u8, 204u8, 70u8, 39u8, 7u8, 43u8, 103u8, 78u8, 39u8, 131u8, + 180u8, 20u8, 39u8, 227u8, 29u8, 228u8, 234u8, 36u8, 155u8, 114u8, + 197u8, 135u8, 185u8, 31u8, 56u8, 247u8, 224u8, 168u8, 254u8, 233u8, + 250u8, 134u8, 186u8, 155u8, 108u8, 84u8, 94u8, 226u8, 207u8, 130u8, + 196u8, 100u8, ], ) } - #[doc = "Claim tokens from an airdrop by providing a Merkle proof."] + #[doc = "Propose and approve a spend of treasury funds."] + #[doc = ""] + #[doc = "## Dispatch Origin"] + #[doc = ""] + #[doc = "Must be [`Config::SpendOrigin`] with the `Success` value being at least"] + #[doc = "`amount` of `asset_kind` in the native asset. The amount of `asset_kind` is converted"] + #[doc = "for assertion using the [`Config::BalanceConverter`]."] #[doc = ""] - #[doc = "Users can claim their tokens by providing a proof of their eligibility."] - #[doc = "The proof is verified against the airdrop's Merkle root."] - #[doc = "Anyone can trigger a claim for any eligible recipient."] + #[doc = "## Details"] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "Create an approved spend for transferring a specific `amount` of `asset_kind` to a"] + #[doc = "designated beneficiary. The spend must be claimed using the `payout` dispatchable within"] + #[doc = "the [`Config::PayoutPeriod`]."] #[doc = ""] - #[doc = "* `origin` - The origin of the call"] - #[doc = "* `airdrop_id` - The ID of the airdrop to claim from"] - #[doc = "* `amount` - The amount of tokens to claim"] - #[doc = "* `merkle_proof` - The Merkle proof verifying eligibility"] + #[doc = "### Parameters"] + #[doc = "- `asset_kind`: An indicator of the specific asset class to be spent."] + #[doc = "- `amount`: The amount to be transferred from the treasury to the `beneficiary`."] + #[doc = "- `beneficiary`: The beneficiary of the spend."] + #[doc = "- `valid_from`: The block number from which the spend can be claimed. It can refer to"] + #[doc = " the past if the resulting spend has not yet expired according to the"] + #[doc = " [`Config::PayoutPeriod`]. If `None`, the spend can be claimed immediately after"] + #[doc = " approval."] #[doc = ""] - #[doc = "# Errors"] + #[doc = "## Events"] #[doc = ""] - #[doc = "* `AirdropNotFound` - If the specified airdrop does not exist"] - #[doc = "* `AlreadyClaimed` - If the recipient has already claimed from this airdrop"] - #[doc = "* `InvalidProof` - If the provided Merkle proof is invalid"] - #[doc = "* `InsufficientAirdropBalance` - If the airdrop doesn't have enough tokens"] - pub fn claim( + #[doc = "Emits [`Event::AssetSpendApproved`] if successful."] + pub fn spend( &self, - airdrop_id: types::claim::AirdropId, - recipient: types::claim::Recipient, - amount: types::claim::Amount, - merkle_proof: types::claim::MerkleProof, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + asset_kind: types::spend::AssetKind, + amount: types::spend::Amount, + beneficiary: types::spend::Beneficiary, + valid_from: types::spend::ValidFrom, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "MerkleAirdrop", - "claim", - types::Claim { airdrop_id, recipient, amount, merkle_proof }, + "TreasuryPallet", + "spend", + types::Spend { + asset_kind: ::subxt::ext::subxt_core::alloc::boxed::Box::new( + asset_kind, + ), + amount, + beneficiary: ::subxt::ext::subxt_core::alloc::boxed::Box::new( + beneficiary, + ), + valid_from, + }, [ - 137u8, 9u8, 80u8, 195u8, 157u8, 215u8, 158u8, 30u8, 26u8, 104u8, 183u8, - 55u8, 102u8, 100u8, 41u8, 40u8, 26u8, 193u8, 255u8, 95u8, 201u8, 240u8, - 18u8, 253u8, 71u8, 117u8, 88u8, 250u8, 192u8, 67u8, 127u8, 159u8, + 64u8, 121u8, 249u8, 219u8, 22u8, 188u8, 167u8, 85u8, 45u8, 27u8, 200u8, + 219u8, 138u8, 17u8, 230u8, 106u8, 145u8, 39u8, 43u8, 161u8, 69u8, 10u8, + 202u8, 251u8, 127u8, 131u8, 0u8, 194u8, 25u8, 153u8, 169u8, 206u8, ], ) } - #[doc = "Delete an airdrop and reclaim any remaining funds."] + #[doc = "Claim a spend."] #[doc = ""] - #[doc = "This function allows the creator of an airdrop to delete it and reclaim"] - #[doc = "any remaining tokens that haven't been claimed."] + #[doc = "## Dispatch Origin"] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "Must be signed"] #[doc = ""] - #[doc = "* `origin` - The origin of the call (must be the airdrop creator)"] - #[doc = "* `airdrop_id` - The ID of the airdrop to delete"] + #[doc = "## Details"] #[doc = ""] - #[doc = "# Errors"] + #[doc = "Spends must be claimed within some temporal bounds. A spend may be claimed within one"] + #[doc = "[`Config::PayoutPeriod`] from the `valid_from` block."] + #[doc = "In case of a payout failure, the spend status must be updated with the `check_status`"] + #[doc = "dispatchable before retrying with the current function."] #[doc = ""] - #[doc = "* `AirdropNotFound` - If the specified airdrop does not exist"] - #[doc = "* `NotAirdropCreator` - If the caller is not the creator of the airdrop"] - pub fn delete_airdrop( + #[doc = "### Parameters"] + #[doc = "- `index`: The spend index."] + #[doc = ""] + #[doc = "## Events"] + #[doc = ""] + #[doc = "Emits [`Event::Paid`] if successful."] + pub fn payout( &self, - airdrop_id: types::delete_airdrop::AirdropId, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { + index: types::payout::Index, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "TreasuryPallet", + "payout", + types::Payout { index }, + [ + 179u8, 254u8, 82u8, 94u8, 248u8, 26u8, 6u8, 34u8, 93u8, 244u8, 186u8, + 199u8, 163u8, 32u8, 110u8, 220u8, 78u8, 11u8, 168u8, 182u8, 169u8, + 56u8, 53u8, 194u8, 168u8, 218u8, 131u8, 38u8, 46u8, 156u8, 93u8, 234u8, + ], + ) + } + #[doc = "Check the status of the spend and remove it from the storage if processed."] + #[doc = ""] + #[doc = "## Dispatch Origin"] + #[doc = ""] + #[doc = "Must be signed."] + #[doc = ""] + #[doc = "## Details"] + #[doc = ""] + #[doc = "The status check is a prerequisite for retrying a failed payout."] + #[doc = "If a spend has either succeeded or expired, it is removed from the storage by this"] + #[doc = "function. In such instances, transaction fees are refunded."] + #[doc = ""] + #[doc = "### Parameters"] + #[doc = "- `index`: The spend index."] + #[doc = ""] + #[doc = "## Events"] + #[doc = ""] + #[doc = "Emits [`Event::PaymentFailed`] if the spend payout has failed."] + #[doc = "Emits [`Event::SpendProcessed`] if the spend payout has succeed."] + pub fn check_status( + &self, + index: types::check_status::Index, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "TreasuryPallet", + "check_status", + types::CheckStatus { index }, + [ + 164u8, 111u8, 10u8, 11u8, 104u8, 237u8, 112u8, 240u8, 104u8, 130u8, + 179u8, 221u8, 54u8, 18u8, 8u8, 172u8, 148u8, 245u8, 110u8, 174u8, 75u8, + 38u8, 46u8, 143u8, 101u8, 232u8, 65u8, 252u8, 36u8, 152u8, 29u8, 209u8, + ], + ) + } + #[doc = "Void previously approved spend."] + #[doc = ""] + #[doc = "## Dispatch Origin"] + #[doc = ""] + #[doc = "Must be [`Config::RejectOrigin`]."] + #[doc = ""] + #[doc = "## Details"] + #[doc = ""] + #[doc = "A spend void is only possible if the payout has not been attempted yet."] + #[doc = ""] + #[doc = "### Parameters"] + #[doc = "- `index`: The spend index."] + #[doc = ""] + #[doc = "## Events"] + #[doc = ""] + #[doc = "Emits [`Event::AssetSpendVoided`] if successful."] + pub fn void_spend( + &self, + index: types::void_spend::Index, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "MerkleAirdrop", - "delete_airdrop", - types::DeleteAirdrop { airdrop_id }, + "TreasuryPallet", + "void_spend", + types::VoidSpend { index }, [ - 34u8, 88u8, 199u8, 36u8, 214u8, 19u8, 124u8, 24u8, 29u8, 222u8, 138u8, - 174u8, 47u8, 199u8, 59u8, 155u8, 118u8, 157u8, 82u8, 96u8, 81u8, 186u8, - 27u8, 96u8, 116u8, 99u8, 185u8, 8u8, 100u8, 34u8, 179u8, 185u8, + 9u8, 212u8, 174u8, 92u8, 43u8, 102u8, 224u8, 124u8, 247u8, 239u8, + 196u8, 68u8, 132u8, 171u8, 116u8, 206u8, 52u8, 23u8, 92u8, 31u8, 156u8, + 160u8, 25u8, 16u8, 125u8, 60u8, 9u8, 109u8, 145u8, 139u8, 102u8, 224u8, ], ) } } } #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_merkle_airdrop::pallet::Event; + pub type Event = runtime_types::pallet_treasury::pallet::Event; pub mod events { use super::runtime_types; #[derive( @@ -14620,25 +14285,17 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A new airdrop has been created."] - #[doc = ""] - #[doc = "Parameters: [airdrop_id, merkle_root]"] - pub struct AirdropCreated { - pub airdrop_id: airdrop_created::AirdropId, - pub airdrop_metadata: airdrop_created::AirdropMetadata, - } - pub mod airdrop_created { + #[doc = "We have ended a spend period and will now allocate funds."] + pub struct Spending { + pub budget_remaining: spending::BudgetRemaining, + } + pub mod spending { use super::runtime_types; - pub type AirdropId = ::core::primitive::u32; - pub type AirdropMetadata = runtime_types::pallet_merkle_airdrop::AirdropMetadata< - ::core::primitive::u32, - ::core::primitive::u128, - ::subxt::ext::subxt_core::utils::AccountId32, - >; + pub type BudgetRemaining = ::core::primitive::u128; } - impl ::subxt::ext::subxt_core::events::StaticEvent for AirdropCreated { - const PALLET: &'static str = "MerkleAirdrop"; - const EVENT: &'static str = "AirdropCreated"; + impl ::subxt::ext::subxt_core::events::StaticEvent for Spending { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "Spending"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -14647,21 +14304,21 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "An airdrop has been funded with tokens."] - #[doc = ""] - #[doc = "Parameters: [airdrop_id, amount]"] - pub struct AirdropFunded { - pub airdrop_id: airdrop_funded::AirdropId, - pub amount: airdrop_funded::Amount, - } - pub mod airdrop_funded { + #[doc = "Some funds have been allocated."] + pub struct Awarded { + pub proposal_index: awarded::ProposalIndex, + pub award: awarded::Award, + pub account: awarded::Account, + } + pub mod awarded { use super::runtime_types; - pub type AirdropId = ::core::primitive::u32; - pub type Amount = ::core::primitive::u128; + pub type ProposalIndex = ::core::primitive::u32; + pub type Award = ::core::primitive::u128; + pub type Account = ::subxt::ext::subxt_core::utils::AccountId32; } - impl ::subxt::ext::subxt_core::events::StaticEvent for AirdropFunded { - const PALLET: &'static str = "MerkleAirdrop"; - const EVENT: &'static str = "AirdropFunded"; + impl ::subxt::ext::subxt_core::events::StaticEvent for Awarded { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "Awarded"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -14670,23 +14327,17 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A user has claimed tokens from an airdrop."] - #[doc = ""] - #[doc = "Parameters: [airdrop_id, account, amount]"] - pub struct Claimed { - pub airdrop_id: claimed::AirdropId, - pub account: claimed::Account, - pub amount: claimed::Amount, - } - pub mod claimed { + #[doc = "Some of our funds have been burnt."] + pub struct Burnt { + pub burnt_funds: burnt::BurntFunds, + } + pub mod burnt { use super::runtime_types; - pub type AirdropId = ::core::primitive::u32; - pub type Account = ::subxt::ext::subxt_core::utils::AccountId32; - pub type Amount = ::core::primitive::u128; + pub type BurntFunds = ::core::primitive::u128; } - impl ::subxt::ext::subxt_core::events::StaticEvent for Claimed { - const PALLET: &'static str = "MerkleAirdrop"; - const EVENT: &'static str = "Claimed"; + impl ::subxt::ext::subxt_core::events::StaticEvent for Burnt { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "Burnt"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -14695,1410 +14346,736 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "An airdrop has been deleted."] - #[doc = ""] - #[doc = "Parameters: [airdrop_id]"] - pub struct AirdropDeleted { - pub airdrop_id: airdrop_deleted::AirdropId, + #[doc = "Spending has finished; this is the amount that rolls over until next spend."] + pub struct Rollover { + pub rollover_balance: rollover::RolloverBalance, } - pub mod airdrop_deleted { + pub mod rollover { use super::runtime_types; - pub type AirdropId = ::core::primitive::u32; + pub type RolloverBalance = ::core::primitive::u128; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for Rollover { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "Rollover"; } - impl ::subxt::ext::subxt_core::events::StaticEvent for AirdropDeleted { - const PALLET: &'static str = "MerkleAirdrop"; - const EVENT: &'static str = "AirdropDeleted"; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Some funds have been deposited."] + pub struct Deposit { + pub value: deposit::Value, } - } - pub mod storage { - use super::runtime_types; - pub mod types { + pub mod deposit { use super::runtime_types; - pub mod airdrop_info { - use super::runtime_types; - pub type AirdropInfo = runtime_types::pallet_merkle_airdrop::AirdropMetadata< - ::core::primitive::u32, - ::core::primitive::u128, - ::subxt::ext::subxt_core::utils::AccountId32, - >; - pub type Param0 = ::core::primitive::u32; - } - pub mod claimed { - use super::runtime_types; - pub type Claimed = (); - pub type Param0 = ::core::primitive::u32; - pub type Param1 = ::subxt::ext::subxt_core::utils::AccountId32; - } - pub mod next_airdrop_id { - use super::runtime_types; - pub type NextAirdropId = ::core::primitive::u32; - } + pub type Value = ::core::primitive::u128; } - pub struct StorageApi; - impl StorageApi { - #[doc = " Stores general info about an airdrop"] - pub fn airdrop_info_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::airdrop_info::AirdropInfo, - (), - (), - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "MerkleAirdrop", - "AirdropInfo", - (), - [ - 38u8, 176u8, 25u8, 251u8, 80u8, 201u8, 118u8, 175u8, 89u8, 80u8, 227u8, - 241u8, 250u8, 0u8, 112u8, 71u8, 133u8, 50u8, 137u8, 13u8, 255u8, 24u8, - 253u8, 237u8, 195u8, 1u8, 192u8, 177u8, 167u8, 248u8, 11u8, 160u8, - ], - ) - } - #[doc = " Stores general info about an airdrop"] - pub fn airdrop_info( - &self, - _0: types::airdrop_info::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::airdrop_info::Param0, - >, - types::airdrop_info::AirdropInfo, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "MerkleAirdrop", - "AirdropInfo", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 38u8, 176u8, 25u8, 251u8, 80u8, 201u8, 118u8, 175u8, 89u8, 80u8, 227u8, - 241u8, 250u8, 0u8, 112u8, 71u8, 133u8, 50u8, 137u8, 13u8, 255u8, 24u8, - 253u8, 237u8, 195u8, 1u8, 192u8, 177u8, 167u8, 248u8, 11u8, 160u8, - ], - ) - } - #[doc = " Storage for claimed status"] - pub fn claimed_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::claimed::Claimed, - (), - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "MerkleAirdrop", - "Claimed", - (), - [ - 214u8, 178u8, 109u8, 48u8, 230u8, 120u8, 107u8, 211u8, 179u8, 251u8, - 164u8, 29u8, 197u8, 154u8, 160u8, 230u8, 112u8, 212u8, 14u8, 157u8, - 248u8, 207u8, 101u8, 159u8, 203u8, 82u8, 199u8, 102u8, 99u8, 239u8, - 162u8, 10u8, - ], - ) - } - #[doc = " Storage for claimed status"] - pub fn claimed_iter1( - &self, - _0: types::claimed::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::claimed::Param0, - >, - types::claimed::Claimed, - (), - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "MerkleAirdrop", - "Claimed", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 214u8, 178u8, 109u8, 48u8, 230u8, 120u8, 107u8, 211u8, 179u8, 251u8, - 164u8, 29u8, 197u8, 154u8, 160u8, 230u8, 112u8, 212u8, 14u8, 157u8, - 248u8, 207u8, 101u8, 159u8, 203u8, 82u8, 199u8, 102u8, 99u8, 239u8, - 162u8, 10u8, - ], - ) - } - #[doc = " Storage for claimed status"] - pub fn claimed( - &self, - _0: types::claimed::Param0, - _1: types::claimed::Param1, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ( - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::claimed::Param0, - >, - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::claimed::Param1, - >, - ), - types::claimed::Claimed, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "MerkleAirdrop", - "Claimed", - ( - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), - ), - [ - 214u8, 178u8, 109u8, 48u8, 230u8, 120u8, 107u8, 211u8, 179u8, 251u8, - 164u8, 29u8, 197u8, 154u8, 160u8, 230u8, 112u8, 212u8, 14u8, 157u8, - 248u8, 207u8, 101u8, 159u8, 203u8, 82u8, 199u8, 102u8, 99u8, 239u8, - 162u8, 10u8, - ], - ) - } - #[doc = " Counter for airdrop IDs"] - pub fn next_airdrop_id( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::next_airdrop_id::NextAirdropId, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "MerkleAirdrop", - "NextAirdropId", - (), - [ - 79u8, 145u8, 145u8, 158u8, 86u8, 58u8, 102u8, 216u8, 133u8, 34u8, - 252u8, 224u8, 222u8, 51u8, 170u8, 3u8, 135u8, 29u8, 99u8, 143u8, 93u8, - 176u8, 69u8, 231u8, 74u8, 214u8, 94u8, 126u8, 227u8, 166u8, 242u8, - 98u8, - ], - ) - } + impl ::subxt::ext::subxt_core::events::StaticEvent for Deposit { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "Deposit"; } - } - pub mod constants { - use super::runtime_types; - pub struct ConstantsApi; - impl ConstantsApi { - #[doc = " The maximum number of proof elements allowed in a Merkle proof."] - pub fn max_proofs( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u32, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "MerkleAirdrop", - "MaxProofs", - [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, - ], - ) - } - #[doc = " The pallet id, used for deriving its sovereign account ID."] - pub fn pallet_id( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - runtime_types::frame_support::PalletId, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "MerkleAirdrop", - "PalletId", - [ - 56u8, 243u8, 53u8, 83u8, 154u8, 179u8, 170u8, 80u8, 133u8, 173u8, 61u8, - 161u8, 47u8, 225u8, 146u8, 21u8, 50u8, 229u8, 248u8, 27u8, 104u8, 58u8, - 129u8, 197u8, 102u8, 160u8, 168u8, 205u8, 154u8, 42u8, 217u8, 53u8, - ], - ) - } - #[doc = " Priority for unsigned claim transactions."] - pub fn unsigned_claim_priority( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u64, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "MerkleAirdrop", - "UnsignedClaimPriority", - [ - 128u8, 214u8, 205u8, 242u8, 181u8, 142u8, 124u8, 231u8, 190u8, 146u8, - 59u8, 226u8, 157u8, 101u8, 103u8, 117u8, 249u8, 65u8, 18u8, 191u8, - 103u8, 119u8, 53u8, 85u8, 81u8, 96u8, 220u8, 42u8, 184u8, 239u8, 42u8, - 246u8, - ], - ) - } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A new spend proposal has been approved."] + pub struct SpendApproved { + pub proposal_index: spend_approved::ProposalIndex, + pub amount: spend_approved::Amount, + pub beneficiary: spend_approved::Beneficiary, + } + pub mod spend_approved { + use super::runtime_types; + pub type ProposalIndex = ::core::primitive::u32; + pub type Amount = ::core::primitive::u128; + pub type Beneficiary = ::subxt::ext::subxt_core::utils::AccountId32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for SpendApproved { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "SpendApproved"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "The inactive funds of the pallet have been updated."] + pub struct UpdatedInactive { + pub reactivated: updated_inactive::Reactivated, + pub deactivated: updated_inactive::Deactivated, + } + pub mod updated_inactive { + use super::runtime_types; + pub type Reactivated = ::core::primitive::u128; + pub type Deactivated = ::core::primitive::u128; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for UpdatedInactive { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "UpdatedInactive"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A new asset spend proposal has been approved."] + pub struct AssetSpendApproved { + pub index: asset_spend_approved::Index, + pub asset_kind: asset_spend_approved::AssetKind, + pub amount: asset_spend_approved::Amount, + pub beneficiary: asset_spend_approved::Beneficiary, + pub valid_from: asset_spend_approved::ValidFrom, + pub expire_at: asset_spend_approved::ExpireAt, + } + pub mod asset_spend_approved { + use super::runtime_types; + pub type Index = ::core::primitive::u32; + pub type AssetKind = (); + pub type Amount = ::core::primitive::u128; + pub type Beneficiary = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ValidFrom = ::core::primitive::u32; + pub type ExpireAt = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for AssetSpendApproved { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "AssetSpendApproved"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "An approved spend was voided."] + pub struct AssetSpendVoided { + pub index: asset_spend_voided::Index, + } + pub mod asset_spend_voided { + use super::runtime_types; + pub type Index = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for AssetSpendVoided { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "AssetSpendVoided"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A payment happened."] + pub struct Paid { + pub index: paid::Index, + pub payment_id: paid::PaymentId, + } + pub mod paid { + use super::runtime_types; + pub type Index = ::core::primitive::u32; + pub type PaymentId = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for Paid { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "Paid"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A payment failed and can be retried."] + pub struct PaymentFailed { + pub index: payment_failed::Index, + pub payment_id: payment_failed::PaymentId, + } + pub mod payment_failed { + use super::runtime_types; + pub type Index = ::core::primitive::u32; + pub type PaymentId = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for PaymentFailed { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "PaymentFailed"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A spend was processed and removed from the storage. It might have been successfully"] + #[doc = "paid or it may have expired."] + pub struct SpendProcessed { + pub index: spend_processed::Index, + } + pub mod spend_processed { + use super::runtime_types; + pub type Index = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for SpendProcessed { + const PALLET: &'static str = "TreasuryPallet"; + const EVENT: &'static str = "SpendProcessed"; } } - } - pub mod treasury_pallet { - use super::{root_mod, runtime_types}; - #[doc = "Error for the treasury pallet."] - pub type Error = runtime_types::pallet_treasury::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_treasury::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; + pub mod storage { + use super::runtime_types; pub mod types { use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Propose and approve a spend of treasury funds."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be [`Config::SpendOrigin`] with the `Success` value being at least `amount`."] - #[doc = ""] - #[doc = "### Details"] - #[doc = "NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the"] - #[doc = "beneficiary."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `amount`: The amount to be transferred from the treasury to the `beneficiary`."] - #[doc = "- `beneficiary`: The destination account for the transfer."] - #[doc = ""] - #[doc = "## Events"] - #[doc = ""] - #[doc = "Emits [`Event::SpendApproved`] if successful."] - pub struct SpendLocal { - #[codec(compact)] - pub amount: spend_local::Amount, - pub beneficiary: spend_local::Beneficiary, + pub mod proposal_count { + use super::runtime_types; + pub type ProposalCount = ::core::primitive::u32; } - pub mod spend_local { + pub mod proposals { use super::runtime_types; - pub type Amount = ::core::primitive::u128; - pub type Beneficiary = ::subxt::ext::subxt_core::utils::MultiAddress< + pub type Proposals = runtime_types::pallet_treasury::Proposal< ::subxt::ext::subxt_core::utils::AccountId32, - (), + ::core::primitive::u128, >; + pub type Param0 = ::core::primitive::u32; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SpendLocal { - const PALLET: &'static str = "TreasuryPallet"; - const CALL: &'static str = "spend_local"; + pub mod deactivated { + use super::runtime_types; + pub type Deactivated = ::core::primitive::u128; } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Force a previously approved proposal to be removed from the approval queue."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be [`Config::RejectOrigin`]."] - #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "The original deposit will no longer be returned."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `proposal_id`: The index of a proposal"] - #[doc = ""] - #[doc = "### Complexity"] - #[doc = "- O(A) where `A` is the number of approvals"] - #[doc = ""] - #[doc = "### Errors"] - #[doc = "- [`Error::ProposalNotApproved`]: The `proposal_id` supplied was not found in the"] - #[doc = " approval queue, i.e., the proposal has not been approved. This could also mean the"] - #[doc = " proposal does not exist altogether, thus there is no way it would have been approved"] - #[doc = " in the first place."] - pub struct RemoveApproval { - #[codec(compact)] - pub proposal_id: remove_approval::ProposalId, - } - pub mod remove_approval { + pub mod approvals { use super::runtime_types; - pub type ProposalId = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for RemoveApproval { - const PALLET: &'static str = "TreasuryPallet"; - const CALL: &'static str = "remove_approval"; + pub type Approvals = + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u32, + >; } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Propose and approve a spend of treasury funds."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be [`Config::SpendOrigin`] with the `Success` value being at least"] - #[doc = "`amount` of `asset_kind` in the native asset. The amount of `asset_kind` is converted"] - #[doc = "for assertion using the [`Config::BalanceConverter`]."] - #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "Create an approved spend for transferring a specific `amount` of `asset_kind` to a"] - #[doc = "designated beneficiary. The spend must be claimed using the `payout` dispatchable within"] - #[doc = "the [`Config::PayoutPeriod`]."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `asset_kind`: An indicator of the specific asset class to be spent."] - #[doc = "- `amount`: The amount to be transferred from the treasury to the `beneficiary`."] - #[doc = "- `beneficiary`: The beneficiary of the spend."] - #[doc = "- `valid_from`: The block number from which the spend can be claimed. It can refer to"] - #[doc = " the past if the resulting spend has not yet expired according to the"] - #[doc = " [`Config::PayoutPeriod`]. If `None`, the spend can be claimed immediately after"] - #[doc = " approval."] - #[doc = ""] - #[doc = "## Events"] - #[doc = ""] - #[doc = "Emits [`Event::AssetSpendApproved`] if successful."] - pub struct Spend { - pub asset_kind: ::subxt::ext::subxt_core::alloc::boxed::Box, - #[codec(compact)] - pub amount: spend::Amount, - pub beneficiary: - ::subxt::ext::subxt_core::alloc::boxed::Box, - pub valid_from: spend::ValidFrom, + pub mod spend_count { + use super::runtime_types; + pub type SpendCount = ::core::primitive::u32; } - pub mod spend { + pub mod spends { use super::runtime_types; - pub type AssetKind = (); - pub type Amount = ::core::primitive::u128; - pub type Beneficiary = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, + pub type Spends = runtime_types::pallet_treasury::SpendStatus< (), + ::core::primitive::u128, + ::subxt::ext::subxt_core::utils::AccountId32, + ::core::primitive::u32, + ::core::primitive::u32, >; - pub type ValidFrom = ::core::option::Option<::core::primitive::u32>; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Spend { - const PALLET: &'static str = "TreasuryPallet"; - const CALL: &'static str = "spend"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Claim a spend."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be signed"] - #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "Spends must be claimed within some temporal bounds. A spend may be claimed within one"] - #[doc = "[`Config::PayoutPeriod`] from the `valid_from` block."] - #[doc = "In case of a payout failure, the spend status must be updated with the `check_status`"] - #[doc = "dispatchable before retrying with the current function."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `index`: The spend index."] - #[doc = ""] - #[doc = "## Events"] - #[doc = ""] - #[doc = "Emits [`Event::Paid`] if successful."] - pub struct Payout { - pub index: payout::Index, + pub type Param0 = ::core::primitive::u32; } - pub mod payout { + pub mod last_spend_period { use super::runtime_types; - pub type Index = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Payout { - const PALLET: &'static str = "TreasuryPallet"; - const CALL: &'static str = "payout"; + pub type LastSpendPeriod = ::core::primitive::u32; } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Check the status of the spend and remove it from the storage if processed."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be signed."] - #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "The status check is a prerequisite for retrying a failed payout."] - #[doc = "If a spend has either succeeded or expired, it is removed from the storage by this"] - #[doc = "function. In such instances, transaction fees are refunded."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `index`: The spend index."] - #[doc = ""] - #[doc = "## Events"] + } + pub struct StorageApi; + impl StorageApi { + #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] + #[doc = " Refer to for migration to `spend`."] #[doc = ""] - #[doc = "Emits [`Event::PaymentFailed`] if the spend payout has failed."] - #[doc = "Emits [`Event::SpendProcessed`] if the spend payout has succeed."] - pub struct CheckStatus { - pub index: check_status::Index, - } - pub mod check_status { - use super::runtime_types; - pub type Index = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CheckStatus { - const PALLET: &'static str = "TreasuryPallet"; - const CALL: &'static str = "check_status"; + #[doc = " Number of proposals that have been made."] + pub fn proposal_count( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::proposal_count::ProposalCount, + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "TreasuryPallet", + "ProposalCount", + (), + [ + 91u8, 238u8, 246u8, 106u8, 95u8, 66u8, 83u8, 134u8, 1u8, 225u8, 164u8, + 216u8, 113u8, 101u8, 203u8, 200u8, 113u8, 97u8, 246u8, 228u8, 140u8, + 29u8, 29u8, 48u8, 176u8, 137u8, 93u8, 230u8, 56u8, 75u8, 51u8, 149u8, + ], + ) } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Void previously approved spend."] - #[doc = ""] - #[doc = "## Dispatch Origin"] + #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] + #[doc = " Refer to for migration to `spend`."] #[doc = ""] - #[doc = "Must be [`Config::RejectOrigin`]."] + #[doc = " Proposals that have been made."] + pub fn proposals_iter( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::proposals::Proposals, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "TreasuryPallet", + "Proposals", + (), + [ + 207u8, 135u8, 145u8, 146u8, 48u8, 10u8, 252u8, 40u8, 20u8, 115u8, + 205u8, 41u8, 173u8, 83u8, 115u8, 46u8, 106u8, 40u8, 130u8, 157u8, + 213u8, 87u8, 45u8, 23u8, 14u8, 167u8, 99u8, 208u8, 153u8, 163u8, 141u8, + 55u8, + ], + ) + } + #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] + #[doc = " Refer to for migration to `spend`."] #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "A spend void is only possible if the payout has not been attempted yet."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `index`: The spend index."] - #[doc = ""] - #[doc = "## Events"] - #[doc = ""] - #[doc = "Emits [`Event::AssetSpendVoided`] if successful."] - pub struct VoidSpend { - pub index: void_spend::Index, - } - pub mod void_spend { - use super::runtime_types; - pub type Index = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for VoidSpend { - const PALLET: &'static str = "TreasuryPallet"; - const CALL: &'static str = "void_spend"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "Propose and approve a spend of treasury funds."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be [`Config::SpendOrigin`] with the `Success` value being at least `amount`."] - #[doc = ""] - #[doc = "### Details"] - #[doc = "NOTE: For record-keeping purposes, the proposer is deemed to be equivalent to the"] - #[doc = "beneficiary."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `amount`: The amount to be transferred from the treasury to the `beneficiary`."] - #[doc = "- `beneficiary`: The destination account for the transfer."] - #[doc = ""] - #[doc = "## Events"] - #[doc = ""] - #[doc = "Emits [`Event::SpendApproved`] if successful."] - pub fn spend_local( + #[doc = " Proposals that have been made."] + pub fn proposals( &self, - amount: types::spend_local::Amount, - beneficiary: types::spend_local::Beneficiary, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + _0: types::proposals::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::proposals::Param0, + >, + types::proposals::Proposals, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "TreasuryPallet", - "spend_local", - types::SpendLocal { amount, beneficiary }, + "Proposals", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 137u8, 171u8, 83u8, 247u8, 245u8, 212u8, 152u8, 127u8, 210u8, 71u8, - 254u8, 134u8, 189u8, 26u8, 249u8, 41u8, 214u8, 175u8, 24u8, 64u8, 33u8, - 90u8, 23u8, 134u8, 44u8, 110u8, 63u8, 46u8, 46u8, 146u8, 222u8, 79u8, + 207u8, 135u8, 145u8, 146u8, 48u8, 10u8, 252u8, 40u8, 20u8, 115u8, + 205u8, 41u8, 173u8, 83u8, 115u8, 46u8, 106u8, 40u8, 130u8, 157u8, + 213u8, 87u8, 45u8, 23u8, 14u8, 167u8, 99u8, 208u8, 153u8, 163u8, 141u8, + 55u8, ], ) } - #[doc = "Force a previously approved proposal to be removed from the approval queue."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be [`Config::RejectOrigin`]."] - #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "The original deposit will no longer be returned."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `proposal_id`: The index of a proposal"] - #[doc = ""] - #[doc = "### Complexity"] - #[doc = "- O(A) where `A` is the number of approvals"] - #[doc = ""] - #[doc = "### Errors"] - #[doc = "- [`Error::ProposalNotApproved`]: The `proposal_id` supplied was not found in the"] - #[doc = " approval queue, i.e., the proposal has not been approved. This could also mean the"] - #[doc = " proposal does not exist altogether, thus there is no way it would have been approved"] - #[doc = " in the first place."] - pub fn remove_approval( + #[doc = " The amount which has been reported as inactive to Currency."] + pub fn deactivated( &self, - proposal_id: types::remove_approval::ProposalId, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::deactivated::Deactivated, + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "TreasuryPallet", - "remove_approval", - types::RemoveApproval { proposal_id }, + "Deactivated", + (), [ - 180u8, 20u8, 39u8, 227u8, 29u8, 228u8, 234u8, 36u8, 155u8, 114u8, - 197u8, 135u8, 185u8, 31u8, 56u8, 247u8, 224u8, 168u8, 254u8, 233u8, - 250u8, 134u8, 186u8, 155u8, 108u8, 84u8, 94u8, 226u8, 207u8, 130u8, - 196u8, 100u8, + 120u8, 221u8, 159u8, 56u8, 161u8, 44u8, 54u8, 233u8, 47u8, 114u8, + 170u8, 150u8, 52u8, 24u8, 137u8, 212u8, 122u8, 247u8, 40u8, 17u8, + 208u8, 130u8, 42u8, 154u8, 33u8, 222u8, 59u8, 116u8, 0u8, 15u8, 79u8, + 123u8, ], ) } - #[doc = "Propose and approve a spend of treasury funds."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be [`Config::SpendOrigin`] with the `Success` value being at least"] - #[doc = "`amount` of `asset_kind` in the native asset. The amount of `asset_kind` is converted"] - #[doc = "for assertion using the [`Config::BalanceConverter`]."] - #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "Create an approved spend for transferring a specific `amount` of `asset_kind` to a"] - #[doc = "designated beneficiary. The spend must be claimed using the `payout` dispatchable within"] - #[doc = "the [`Config::PayoutPeriod`]."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `asset_kind`: An indicator of the specific asset class to be spent."] - #[doc = "- `amount`: The amount to be transferred from the treasury to the `beneficiary`."] - #[doc = "- `beneficiary`: The beneficiary of the spend."] - #[doc = "- `valid_from`: The block number from which the spend can be claimed. It can refer to"] - #[doc = " the past if the resulting spend has not yet expired according to the"] - #[doc = " [`Config::PayoutPeriod`]. If `None`, the spend can be claimed immediately after"] - #[doc = " approval."] - #[doc = ""] - #[doc = "## Events"] + #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] + #[doc = " Refer to for migration to `spend`."] #[doc = ""] - #[doc = "Emits [`Event::AssetSpendApproved`] if successful."] - pub fn spend( + #[doc = " Proposal indices that have been approved but not yet awarded."] + pub fn approvals( &self, - asset_kind: types::spend::AssetKind, - amount: types::spend::Amount, - beneficiary: types::spend::Beneficiary, - valid_from: types::spend::ValidFrom, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::approvals::Approvals, + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "TreasuryPallet", - "spend", - types::Spend { - asset_kind: ::subxt::ext::subxt_core::alloc::boxed::Box::new( - asset_kind, - ), - amount, - beneficiary: ::subxt::ext::subxt_core::alloc::boxed::Box::new( - beneficiary, - ), - valid_from, - }, + "Approvals", + (), [ - 64u8, 121u8, 249u8, 219u8, 22u8, 188u8, 167u8, 85u8, 45u8, 27u8, 200u8, - 219u8, 138u8, 17u8, 230u8, 106u8, 145u8, 39u8, 43u8, 161u8, 69u8, 10u8, - 202u8, 251u8, 127u8, 131u8, 0u8, 194u8, 25u8, 153u8, 169u8, 206u8, + 78u8, 147u8, 186u8, 235u8, 17u8, 40u8, 247u8, 235u8, 67u8, 222u8, 3u8, + 14u8, 248u8, 17u8, 67u8, 180u8, 93u8, 161u8, 64u8, 35u8, 119u8, 194u8, + 187u8, 226u8, 135u8, 162u8, 147u8, 174u8, 139u8, 72u8, 99u8, 212u8, ], ) } - #[doc = "Claim a spend."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be signed"] - #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "Spends must be claimed within some temporal bounds. A spend may be claimed within one"] - #[doc = "[`Config::PayoutPeriod`] from the `valid_from` block."] - #[doc = "In case of a payout failure, the spend status must be updated with the `check_status`"] - #[doc = "dispatchable before retrying with the current function."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `index`: The spend index."] - #[doc = ""] - #[doc = "## Events"] - #[doc = ""] - #[doc = "Emits [`Event::Paid`] if successful."] - pub fn payout( + #[doc = " The count of spends that have been made."] + pub fn spend_count( &self, - index: types::payout::Index, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::spend_count::SpendCount, + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "TreasuryPallet", - "payout", - types::Payout { index }, + "SpendCount", + (), [ - 179u8, 254u8, 82u8, 94u8, 248u8, 26u8, 6u8, 34u8, 93u8, 244u8, 186u8, - 199u8, 163u8, 32u8, 110u8, 220u8, 78u8, 11u8, 168u8, 182u8, 169u8, - 56u8, 53u8, 194u8, 168u8, 218u8, 131u8, 38u8, 46u8, 156u8, 93u8, 234u8, + 220u8, 74u8, 248u8, 52u8, 243u8, 209u8, 42u8, 236u8, 27u8, 98u8, 76u8, + 153u8, 129u8, 176u8, 34u8, 177u8, 33u8, 132u8, 21u8, 71u8, 206u8, + 146u8, 222u8, 44u8, 232u8, 246u8, 205u8, 92u8, 240u8, 136u8, 182u8, + 30u8, ], ) } - #[doc = "Check the status of the spend and remove it from the storage if processed."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be signed."] - #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "The status check is a prerequisite for retrying a failed payout."] - #[doc = "If a spend has either succeeded or expired, it is removed from the storage by this"] - #[doc = "function. In such instances, transaction fees are refunded."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `index`: The spend index."] - #[doc = ""] - #[doc = "## Events"] - #[doc = ""] - #[doc = "Emits [`Event::PaymentFailed`] if the spend payout has failed."] - #[doc = "Emits [`Event::SpendProcessed`] if the spend payout has succeed."] - pub fn check_status( + #[doc = " Spends that have been approved and being processed."] + pub fn spends_iter( &self, - index: types::check_status::Index, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "TreasuryPallet", - "check_status", - types::CheckStatus { index }, - [ - 164u8, 111u8, 10u8, 11u8, 104u8, 237u8, 112u8, 240u8, 104u8, 130u8, - 179u8, 221u8, 54u8, 18u8, 8u8, 172u8, 148u8, 245u8, 110u8, 174u8, 75u8, - 38u8, 46u8, 143u8, 101u8, 232u8, 65u8, 252u8, 36u8, 152u8, 29u8, 209u8, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::spends::Spends, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "TreasuryPallet", + "Spends", + (), + [ + 140u8, 4u8, 241u8, 80u8, 4u8, 219u8, 107u8, 152u8, 206u8, 175u8, 107u8, + 172u8, 208u8, 71u8, 174u8, 99u8, 198u8, 52u8, 142u8, 126u8, 145u8, + 171u8, 254u8, 9u8, 235u8, 158u8, 186u8, 101u8, 140u8, 200u8, 96u8, + 168u8, ], ) } - #[doc = "Void previously approved spend."] - #[doc = ""] - #[doc = "## Dispatch Origin"] - #[doc = ""] - #[doc = "Must be [`Config::RejectOrigin`]."] - #[doc = ""] - #[doc = "## Details"] - #[doc = ""] - #[doc = "A spend void is only possible if the payout has not been attempted yet."] - #[doc = ""] - #[doc = "### Parameters"] - #[doc = "- `index`: The spend index."] - #[doc = ""] - #[doc = "## Events"] - #[doc = ""] - #[doc = "Emits [`Event::AssetSpendVoided`] if successful."] - pub fn void_spend( + #[doc = " Spends that have been approved and being processed."] + pub fn spends( &self, - index: types::void_spend::Index, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + _0: types::spends::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::spends::Param0, + >, + types::spends::Spends, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "TreasuryPallet", - "void_spend", - types::VoidSpend { index }, + "Spends", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 9u8, 212u8, 174u8, 92u8, 43u8, 102u8, 224u8, 124u8, 247u8, 239u8, - 196u8, 68u8, 132u8, 171u8, 116u8, 206u8, 52u8, 23u8, 92u8, 31u8, 156u8, - 160u8, 25u8, 16u8, 125u8, 60u8, 9u8, 109u8, 145u8, 139u8, 102u8, 224u8, + 140u8, 4u8, 241u8, 80u8, 4u8, 219u8, 107u8, 152u8, 206u8, 175u8, 107u8, + 172u8, 208u8, 71u8, 174u8, 99u8, 198u8, 52u8, 142u8, 126u8, 145u8, + 171u8, 254u8, 9u8, 235u8, 158u8, 186u8, 101u8, 140u8, 200u8, 96u8, + 168u8, + ], + ) + } + #[doc = " The blocknumber for the last triggered spend period."] + pub fn last_spend_period( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::last_spend_period::LastSpendPeriod, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "TreasuryPallet", + "LastSpendPeriod", + (), + [ + 6u8, 200u8, 107u8, 132u8, 60u8, 31u8, 24u8, 196u8, 108u8, 227u8, 5u8, + 63u8, 249u8, 139u8, 82u8, 140u8, 169u8, 242u8, 118u8, 93u8, 83u8, + 155u8, 120u8, 175u8, 224u8, 227u8, 39u8, 39u8, 255u8, 247u8, 79u8, + 30u8, ], ) } } } - #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_treasury::pallet::Event; - pub mod events { + pub mod constants { use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "We have ended a spend period and will now allocate funds."] - pub struct Spending { - pub budget_remaining: spending::BudgetRemaining, - } - pub mod spending { - use super::runtime_types; - pub type BudgetRemaining = ::core::primitive::u128; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Spending { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "Spending"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Some funds have been allocated."] - pub struct Awarded { - pub proposal_index: awarded::ProposalIndex, - pub award: awarded::Award, - pub account: awarded::Account, + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " Period between successive spends."] + pub fn spend_period( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "TreasuryPallet", + "SpendPeriod", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " Percentage of spare funds (if any) that are burnt per spend period."] + pub fn burn( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + runtime_types::sp_arithmetic::per_things::Permill, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "TreasuryPallet", + "Burn", + [ + 65u8, 93u8, 120u8, 165u8, 204u8, 81u8, 159u8, 163u8, 93u8, 135u8, + 114u8, 121u8, 147u8, 35u8, 215u8, 213u8, 4u8, 223u8, 83u8, 37u8, 225u8, + 200u8, 189u8, 156u8, 140u8, 36u8, 58u8, 46u8, 42u8, 232u8, 155u8, 0u8, + ], + ) + } + #[doc = " The treasury's pallet id, used for deriving its sovereign account ID."] + pub fn pallet_id( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + runtime_types::frame_support::PalletId, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "TreasuryPallet", + "PalletId", + [ + 56u8, 243u8, 53u8, 83u8, 154u8, 179u8, 170u8, 80u8, 133u8, 173u8, 61u8, + 161u8, 47u8, 225u8, 146u8, 21u8, 50u8, 229u8, 248u8, 27u8, 104u8, 58u8, + 129u8, 197u8, 102u8, 160u8, 168u8, 205u8, 154u8, 42u8, 217u8, 53u8, + ], + ) + } + #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] + #[doc = " Refer to for migration to `spend`."] + #[doc = ""] + #[doc = " The maximum number of approvals that can wait in the spending queue."] + #[doc = ""] + #[doc = " NOTE: This parameter is also used within the Bounties Pallet extension if enabled."] + pub fn max_approvals( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "TreasuryPallet", + "MaxApprovals", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " The period during which an approved treasury spend has to be claimed."] + pub fn payout_period( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "TreasuryPallet", + "PayoutPeriod", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " Gets this pallet's derived pot account."] + pub fn pot_account( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::subxt::ext::subxt_core::utils::AccountId32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "TreasuryPallet", + "pot_account", + [ + 115u8, 233u8, 13u8, 223u8, 88u8, 20u8, 202u8, 139u8, 153u8, 28u8, + 155u8, 157u8, 224u8, 66u8, 3u8, 250u8, 23u8, 53u8, 88u8, 168u8, 211u8, + 204u8, 122u8, 166u8, 248u8, 23u8, 174u8, 225u8, 99u8, 108u8, 89u8, + 135u8, + ], + ) + } } - pub mod awarded { + } + } + pub mod origins { + use super::{root_mod, runtime_types}; + } + pub mod recovery { + use super::{root_mod, runtime_types}; + #[doc = "The `Error` enum of this pallet."] + pub type Error = runtime_types::pallet_recovery::pallet::Error; + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::pallet_recovery::pallet::Call; + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + pub mod types { use super::runtime_types; - pub type ProposalIndex = ::core::primitive::u32; - pub type Award = ::core::primitive::u128; - pub type Account = ::subxt::ext::subxt_core::utils::AccountId32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Awarded { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "Awarded"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Some of our funds have been burnt."] - pub struct Burnt { - pub burnt_funds: burnt::BurntFunds, - } - pub mod burnt { - use super::runtime_types; - pub type BurntFunds = ::core::primitive::u128; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Burnt { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "Burnt"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Spending has finished; this is the amount that rolls over until next spend."] - pub struct Rollover { - pub rollover_balance: rollover::RolloverBalance, - } - pub mod rollover { - use super::runtime_types; - pub type RolloverBalance = ::core::primitive::u128; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Rollover { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "Rollover"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Some funds have been deposited."] - pub struct Deposit { - pub value: deposit::Value, - } - pub mod deposit { - use super::runtime_types; - pub type Value = ::core::primitive::u128; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Deposit { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "Deposit"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A new spend proposal has been approved."] - pub struct SpendApproved { - pub proposal_index: spend_approved::ProposalIndex, - pub amount: spend_approved::Amount, - pub beneficiary: spend_approved::Beneficiary, - } - pub mod spend_approved { - use super::runtime_types; - pub type ProposalIndex = ::core::primitive::u32; - pub type Amount = ::core::primitive::u128; - pub type Beneficiary = ::subxt::ext::subxt_core::utils::AccountId32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for SpendApproved { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "SpendApproved"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "The inactive funds of the pallet have been updated."] - pub struct UpdatedInactive { - pub reactivated: updated_inactive::Reactivated, - pub deactivated: updated_inactive::Deactivated, - } - pub mod updated_inactive { - use super::runtime_types; - pub type Reactivated = ::core::primitive::u128; - pub type Deactivated = ::core::primitive::u128; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for UpdatedInactive { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "UpdatedInactive"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A new asset spend proposal has been approved."] - pub struct AssetSpendApproved { - pub index: asset_spend_approved::Index, - pub asset_kind: asset_spend_approved::AssetKind, - pub amount: asset_spend_approved::Amount, - pub beneficiary: asset_spend_approved::Beneficiary, - pub valid_from: asset_spend_approved::ValidFrom, - pub expire_at: asset_spend_approved::ExpireAt, - } - pub mod asset_spend_approved { - use super::runtime_types; - pub type Index = ::core::primitive::u32; - pub type AssetKind = (); - pub type Amount = ::core::primitive::u128; - pub type Beneficiary = ::subxt::ext::subxt_core::utils::AccountId32; - pub type ValidFrom = ::core::primitive::u32; - pub type ExpireAt = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for AssetSpendApproved { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "AssetSpendApproved"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "An approved spend was voided."] - pub struct AssetSpendVoided { - pub index: asset_spend_voided::Index, - } - pub mod asset_spend_voided { - use super::runtime_types; - pub type Index = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for AssetSpendVoided { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "AssetSpendVoided"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A payment happened."] - pub struct Paid { - pub index: paid::Index, - pub payment_id: paid::PaymentId, - } - pub mod paid { - use super::runtime_types; - pub type Index = ::core::primitive::u32; - pub type PaymentId = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Paid { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "Paid"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A payment failed and can be retried."] - pub struct PaymentFailed { - pub index: payment_failed::Index, - pub payment_id: payment_failed::PaymentId, - } - pub mod payment_failed { - use super::runtime_types; - pub type Index = ::core::primitive::u32; - pub type PaymentId = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for PaymentFailed { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "PaymentFailed"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A spend was processed and removed from the storage. It might have been successfully"] - #[doc = "paid or it may have expired."] - pub struct SpendProcessed { - pub index: spend_processed::Index, - } - pub mod spend_processed { - use super::runtime_types; - pub type Index = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for SpendProcessed { - const PALLET: &'static str = "TreasuryPallet"; - const EVENT: &'static str = "SpendProcessed"; - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod proposal_count { - use super::runtime_types; - pub type ProposalCount = ::core::primitive::u32; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Send a call through a recovered account."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_ and registered to"] + #[doc = "be able to make calls on behalf of the recovered account."] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `account`: The recovered account you want to make a call on-behalf-of."] + #[doc = "- `call`: The call you want to make with the recovered account."] + pub struct AsRecovered { + pub account: as_recovered::Account, + pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, } - pub mod proposals { + pub mod as_recovered { use super::runtime_types; - pub type Proposals = runtime_types::pallet_treasury::Proposal< + pub type Account = ::subxt::ext::subxt_core::utils::MultiAddress< ::subxt::ext::subxt_core::utils::AccountId32, - ::core::primitive::u128, + (), >; - pub type Param0 = ::core::primitive::u32; - } - pub mod deactivated { - use super::runtime_types; - pub type Deactivated = ::core::primitive::u128; + pub type Call = runtime_types::quantus_runtime::RuntimeCall; } - pub mod approvals { - use super::runtime_types; - pub type Approvals = - runtime_types::bounded_collections::bounded_vec::BoundedVec< - ::core::primitive::u32, - >; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for AsRecovered { + const PALLET: &'static str = "Recovery"; + const CALL: &'static str = "as_recovered"; } - pub mod spend_count { - use super::runtime_types; - pub type SpendCount = ::core::primitive::u32; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Allow ROOT to bypass the recovery process and set a rescuer account"] + #[doc = "for a lost account directly."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _ROOT_."] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `lost`: The \"lost account\" to be recovered."] + #[doc = "- `rescuer`: The \"rescuer account\" which can call as the lost account."] + pub struct SetRecovered { + pub lost: set_recovered::Lost, + pub rescuer: set_recovered::Rescuer, } - pub mod spends { + pub mod set_recovered { use super::runtime_types; - pub type Spends = runtime_types::pallet_treasury::SpendStatus< + pub type Lost = ::subxt::ext::subxt_core::utils::MultiAddress< + ::subxt::ext::subxt_core::utils::AccountId32, (), - ::core::primitive::u128, + >; + pub type Rescuer = ::subxt::ext::subxt_core::utils::MultiAddress< ::subxt::ext::subxt_core::utils::AccountId32, - ::core::primitive::u32, - ::core::primitive::u32, + (), >; - pub type Param0 = ::core::primitive::u32; } - pub mod last_spend_period { - use super::runtime_types; - pub type LastSpendPeriod = ::core::primitive::u32; + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SetRecovered { + const PALLET: &'static str = "Recovery"; + const CALL: &'static str = "set_recovered"; } - } - pub struct StorageApi; - impl StorageApi { - #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] - #[doc = " Refer to for migration to `spend`."] + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Create a recovery configuration for your account. This makes your account recoverable."] #[doc = ""] - #[doc = " Number of proposals that have been made."] - pub fn proposal_count( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::proposal_count::ProposalCount, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "TreasuryPallet", - "ProposalCount", - (), - [ - 91u8, 238u8, 246u8, 106u8, 95u8, 66u8, 83u8, 134u8, 1u8, 225u8, 164u8, - 216u8, 113u8, 101u8, 203u8, 200u8, 113u8, 97u8, 246u8, 228u8, 140u8, - 29u8, 29u8, 48u8, 176u8, 137u8, 93u8, 230u8, 56u8, 75u8, 51u8, 149u8, - ], - ) - } - #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] - #[doc = " Refer to for migration to `spend`."] + #[doc = "Payment: `ConfigDepositBase` + `FriendDepositFactor` * #_of_friends balance"] + #[doc = "will be reserved for storing the recovery configuration. This deposit is returned"] + #[doc = "in full when the user calls `remove_recovery`."] #[doc = ""] - #[doc = " Proposals that have been made."] - pub fn proposals_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::proposals::Proposals, - (), - (), - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "TreasuryPallet", - "Proposals", - (), - [ - 207u8, 135u8, 145u8, 146u8, 48u8, 10u8, 252u8, 40u8, 20u8, 115u8, - 205u8, 41u8, 173u8, 83u8, 115u8, 46u8, 106u8, 40u8, 130u8, 157u8, - 213u8, 87u8, 45u8, 23u8, 14u8, 167u8, 99u8, 208u8, 153u8, 163u8, 141u8, - 55u8, - ], - ) - } - #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] - #[doc = " Refer to for migration to `spend`."] + #[doc = "The dispatch origin for this call must be _Signed_."] #[doc = ""] - #[doc = " Proposals that have been made."] - pub fn proposals( - &self, - _0: types::proposals::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::proposals::Param0, - >, - types::proposals::Proposals, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "TreasuryPallet", - "Proposals", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 207u8, 135u8, 145u8, 146u8, 48u8, 10u8, 252u8, 40u8, 20u8, 115u8, - 205u8, 41u8, 173u8, 83u8, 115u8, 46u8, 106u8, 40u8, 130u8, 157u8, - 213u8, 87u8, 45u8, 23u8, 14u8, 167u8, 99u8, 208u8, 153u8, 163u8, 141u8, - 55u8, - ], - ) + #[doc = "Parameters:"] + #[doc = "- `friends`: A list of friends you trust to vouch for recovery attempts. Should be"] + #[doc = " ordered and contain no duplicate values."] + #[doc = "- `threshold`: The number of friends that must vouch for a recovery attempt before the"] + #[doc = " account can be recovered. Should be less than or equal to the length of the list of"] + #[doc = " friends."] + #[doc = "- `delay_period`: The number of blocks after a recovery attempt is initialized that"] + #[doc = " needs to pass before the account can be recovered."] + pub struct CreateRecovery { + pub friends: create_recovery::Friends, + pub threshold: create_recovery::Threshold, + pub delay_period: create_recovery::DelayPeriod, } - #[doc = " The amount which has been reported as inactive to Currency."] - pub fn deactivated( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::deactivated::Deactivated, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "TreasuryPallet", - "Deactivated", - (), - [ - 120u8, 221u8, 159u8, 56u8, 161u8, 44u8, 54u8, 233u8, 47u8, 114u8, - 170u8, 150u8, 52u8, 24u8, 137u8, 212u8, 122u8, 247u8, 40u8, 17u8, - 208u8, 130u8, 42u8, 154u8, 33u8, 222u8, 59u8, 116u8, 0u8, 15u8, 79u8, - 123u8, - ], - ) + pub mod create_recovery { + use super::runtime_types; + pub type Friends = ::subxt::ext::subxt_core::alloc::vec::Vec< + ::subxt::ext::subxt_core::utils::AccountId32, + >; + pub type Threshold = ::core::primitive::u16; + pub type DelayPeriod = ::core::primitive::u32; } - #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] - #[doc = " Refer to for migration to `spend`."] + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CreateRecovery { + const PALLET: &'static str = "Recovery"; + const CALL: &'static str = "create_recovery"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Initiate the process for recovering a recoverable account."] #[doc = ""] - #[doc = " Proposal indices that have been approved but not yet awarded."] - pub fn approvals( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::approvals::Approvals, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "TreasuryPallet", - "Approvals", - (), - [ - 78u8, 147u8, 186u8, 235u8, 17u8, 40u8, 247u8, 235u8, 67u8, 222u8, 3u8, - 14u8, 248u8, 17u8, 67u8, 180u8, 93u8, 161u8, 64u8, 35u8, 119u8, 194u8, - 187u8, 226u8, 135u8, 162u8, 147u8, 174u8, 139u8, 72u8, 99u8, 212u8, - ], - ) + #[doc = "Payment: `RecoveryDeposit` balance will be reserved for initiating the"] + #[doc = "recovery process. This deposit will always be repatriated to the account"] + #[doc = "trying to be recovered. See `close_recovery`."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `account`: The lost account that you want to recover. This account needs to be"] + #[doc = " recoverable (i.e. have a recovery configuration)."] + pub struct InitiateRecovery { + pub account: initiate_recovery::Account, } - #[doc = " The count of spends that have been made."] - pub fn spend_count( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::spend_count::SpendCount, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "TreasuryPallet", - "SpendCount", + pub mod initiate_recovery { + use super::runtime_types; + pub type Account = ::subxt::ext::subxt_core::utils::MultiAddress< + ::subxt::ext::subxt_core::utils::AccountId32, (), - [ - 220u8, 74u8, 248u8, 52u8, 243u8, 209u8, 42u8, 236u8, 27u8, 98u8, 76u8, - 153u8, 129u8, 176u8, 34u8, 177u8, 33u8, 132u8, 21u8, 71u8, 206u8, - 146u8, 222u8, 44u8, 232u8, 246u8, 205u8, 92u8, 240u8, 136u8, 182u8, - 30u8, - ], - ) + >; } - #[doc = " Spends that have been approved and being processed."] - pub fn spends_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::spends::Spends, - (), - (), - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "TreasuryPallet", - "Spends", - (), - [ - 140u8, 4u8, 241u8, 80u8, 4u8, 219u8, 107u8, 152u8, 206u8, 175u8, 107u8, - 172u8, 208u8, 71u8, 174u8, 99u8, 198u8, 52u8, 142u8, 126u8, 145u8, - 171u8, 254u8, 9u8, 235u8, 158u8, 186u8, 101u8, 140u8, 200u8, 96u8, - 168u8, - ], - ) - } - #[doc = " Spends that have been approved and being processed."] - pub fn spends( - &self, - _0: types::spends::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::spends::Param0, - >, - types::spends::Spends, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "TreasuryPallet", - "Spends", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 140u8, 4u8, 241u8, 80u8, 4u8, 219u8, 107u8, 152u8, 206u8, 175u8, 107u8, - 172u8, 208u8, 71u8, 174u8, 99u8, 198u8, 52u8, 142u8, 126u8, 145u8, - 171u8, 254u8, 9u8, 235u8, 158u8, 186u8, 101u8, 140u8, 200u8, 96u8, - 168u8, - ], - ) - } - #[doc = " The blocknumber for the last triggered spend period."] - pub fn last_spend_period( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::last_spend_period::LastSpendPeriod, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "TreasuryPallet", - "LastSpendPeriod", - (), - [ - 6u8, 200u8, 107u8, 132u8, 60u8, 31u8, 24u8, 196u8, 108u8, 227u8, 5u8, - 63u8, 249u8, 139u8, 82u8, 140u8, 169u8, 242u8, 118u8, 93u8, 83u8, - 155u8, 120u8, 175u8, 224u8, 227u8, 39u8, 39u8, 255u8, 247u8, 79u8, - 30u8, - ], - ) - } - } - } - pub mod constants { - use super::runtime_types; - pub struct ConstantsApi; - impl ConstantsApi { - #[doc = " Period between successive spends."] - pub fn spend_period( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u32, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "TreasuryPallet", - "SpendPeriod", - [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, - ], - ) - } - #[doc = " Percentage of spare funds (if any) that are burnt per spend period."] - pub fn burn( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - runtime_types::sp_arithmetic::per_things::Permill, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "TreasuryPallet", - "Burn", - [ - 65u8, 93u8, 120u8, 165u8, 204u8, 81u8, 159u8, 163u8, 93u8, 135u8, - 114u8, 121u8, 147u8, 35u8, 215u8, 213u8, 4u8, 223u8, 83u8, 37u8, 225u8, - 200u8, 189u8, 156u8, 140u8, 36u8, 58u8, 46u8, 42u8, 232u8, 155u8, 0u8, - ], - ) - } - #[doc = " The treasury's pallet id, used for deriving its sovereign account ID."] - pub fn pallet_id( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - runtime_types::frame_support::PalletId, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "TreasuryPallet", - "PalletId", - [ - 56u8, 243u8, 53u8, 83u8, 154u8, 179u8, 170u8, 80u8, 133u8, 173u8, 61u8, - 161u8, 47u8, 225u8, 146u8, 21u8, 50u8, 229u8, 248u8, 27u8, 104u8, 58u8, - 129u8, 197u8, 102u8, 160u8, 168u8, 205u8, 154u8, 42u8, 217u8, 53u8, - ], - ) - } - #[doc = " DEPRECATED: associated with `spend_local` call and will be removed in May 2025."] - #[doc = " Refer to for migration to `spend`."] - #[doc = ""] - #[doc = " The maximum number of approvals that can wait in the spending queue."] - #[doc = ""] - #[doc = " NOTE: This parameter is also used within the Bounties Pallet extension if enabled."] - pub fn max_approvals( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u32, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "TreasuryPallet", - "MaxApprovals", - [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, - ], - ) - } - #[doc = " The period during which an approved treasury spend has to be claimed."] - pub fn payout_period( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u32, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "TreasuryPallet", - "PayoutPeriod", - [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, - ], - ) - } - #[doc = " Gets this pallet's derived pot account."] - pub fn pot_account( - &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "TreasuryPallet", - "pot_account", - [ - 115u8, 233u8, 13u8, 223u8, 88u8, 20u8, 202u8, 139u8, 153u8, 28u8, - 155u8, 157u8, 224u8, 66u8, 3u8, 250u8, 23u8, 53u8, 88u8, 168u8, 211u8, - 204u8, 122u8, 166u8, 248u8, 23u8, 174u8, 225u8, 99u8, 108u8, 89u8, - 135u8, - ], - ) + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for InitiateRecovery { + const PALLET: &'static str = "Recovery"; + const CALL: &'static str = "initiate_recovery"; } - } - } - } - pub mod origins { - use super::{root_mod, runtime_types}; - } - pub mod recovery { - use super::{root_mod, runtime_types}; - #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_recovery::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_recovery::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, @@ -16110,29 +15087,36 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Send a call through a recovered account."] + #[doc = "Allow a \"friend\" of a recoverable account to vouch for an active recovery"] + #[doc = "process for that account."] #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_ and registered to"] - #[doc = "be able to make calls on behalf of the recovered account."] + #[doc = "The dispatch origin for this call must be _Signed_ and must be a \"friend\""] + #[doc = "for the recoverable account."] #[doc = ""] #[doc = "Parameters:"] - #[doc = "- `account`: The recovered account you want to make a call on-behalf-of."] - #[doc = "- `call`: The call you want to make with the recovered account."] - pub struct AsRecovered { - pub account: as_recovered::Account, - pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, + #[doc = "- `lost`: The lost account that you want to recover."] + #[doc = "- `rescuer`: The account trying to rescue the lost account that you want to vouch for."] + #[doc = ""] + #[doc = "The combination of these two parameters must point to an active recovery"] + #[doc = "process."] + pub struct VouchRecovery { + pub lost: vouch_recovery::Lost, + pub rescuer: vouch_recovery::Rescuer, } - pub mod as_recovered { + pub mod vouch_recovery { use super::runtime_types; - pub type Account = ::subxt::ext::subxt_core::utils::MultiAddress< + pub type Lost = ::subxt::ext::subxt_core::utils::MultiAddress< + ::subxt::ext::subxt_core::utils::AccountId32, + (), + >; + pub type Rescuer = ::subxt::ext::subxt_core::utils::MultiAddress< ::subxt::ext::subxt_core::utils::AccountId32, (), >; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for AsRecovered { + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for VouchRecovery { const PALLET: &'static str = "Recovery"; - const CALL: &'static str = "as_recovered"; + const CALL: &'static str = "vouch_recovery"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -16145,32 +15129,28 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Allow ROOT to bypass the recovery process and set a rescuer account"] - #[doc = "for a lost account directly."] + #[doc = "Allow a successful rescuer to claim their recovered account."] #[doc = ""] - #[doc = "The dispatch origin for this call must be _ROOT_."] + #[doc = "The dispatch origin for this call must be _Signed_ and must be a \"rescuer\""] + #[doc = "who has successfully completed the account recovery process: collected"] + #[doc = "`threshold` or more vouches, waited `delay_period` blocks since initiation."] #[doc = ""] #[doc = "Parameters:"] - #[doc = "- `lost`: The \"lost account\" to be recovered."] - #[doc = "- `rescuer`: The \"rescuer account\" which can call as the lost account."] - pub struct SetRecovered { - pub lost: set_recovered::Lost, - pub rescuer: set_recovered::Rescuer, + #[doc = "- `account`: The lost account that you want to claim has been successfully recovered by"] + #[doc = " you."] + pub struct ClaimRecovery { + pub account: claim_recovery::Account, } - pub mod set_recovered { + pub mod claim_recovery { use super::runtime_types; - pub type Lost = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - pub type Rescuer = ::subxt::ext::subxt_core::utils::MultiAddress< + pub type Account = ::subxt::ext::subxt_core::utils::MultiAddress< ::subxt::ext::subxt_core::utils::AccountId32, (), >; } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SetRecovered { + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ClaimRecovery { const PALLET: &'static str = "Recovery"; - const CALL: &'static str = "set_recovered"; + const CALL: &'static str = "claim_recovery"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -16183,164 +15163,8 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Create a recovery configuration for your account. This makes your account recoverable."] - #[doc = ""] - #[doc = "Payment: `ConfigDepositBase` + `FriendDepositFactor` * #_of_friends balance"] - #[doc = "will be reserved for storing the recovery configuration. This deposit is returned"] - #[doc = "in full when the user calls `remove_recovery`."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - #[doc = ""] - #[doc = "Parameters:"] - #[doc = "- `friends`: A list of friends you trust to vouch for recovery attempts. Should be"] - #[doc = " ordered and contain no duplicate values."] - #[doc = "- `threshold`: The number of friends that must vouch for a recovery attempt before the"] - #[doc = " account can be recovered. Should be less than or equal to the length of the list of"] - #[doc = " friends."] - #[doc = "- `delay_period`: The number of blocks after a recovery attempt is initialized that"] - #[doc = " needs to pass before the account can be recovered."] - pub struct CreateRecovery { - pub friends: create_recovery::Friends, - pub threshold: create_recovery::Threshold, - pub delay_period: create_recovery::DelayPeriod, - } - pub mod create_recovery { - use super::runtime_types; - pub type Friends = ::subxt::ext::subxt_core::alloc::vec::Vec< - ::subxt::ext::subxt_core::utils::AccountId32, - >; - pub type Threshold = ::core::primitive::u16; - pub type DelayPeriod = ::core::primitive::u32; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CreateRecovery { - const PALLET: &'static str = "Recovery"; - const CALL: &'static str = "create_recovery"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Initiate the process for recovering a recoverable account."] - #[doc = ""] - #[doc = "Payment: `RecoveryDeposit` balance will be reserved for initiating the"] - #[doc = "recovery process. This deposit will always be repatriated to the account"] - #[doc = "trying to be recovered. See `close_recovery`."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - #[doc = ""] - #[doc = "Parameters:"] - #[doc = "- `account`: The lost account that you want to recover. This account needs to be"] - #[doc = " recoverable (i.e. have a recovery configuration)."] - pub struct InitiateRecovery { - pub account: initiate_recovery::Account, - } - pub mod initiate_recovery { - use super::runtime_types; - pub type Account = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for InitiateRecovery { - const PALLET: &'static str = "Recovery"; - const CALL: &'static str = "initiate_recovery"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Allow a \"friend\" of a recoverable account to vouch for an active recovery"] - #[doc = "process for that account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_ and must be a \"friend\""] - #[doc = "for the recoverable account."] - #[doc = ""] - #[doc = "Parameters:"] - #[doc = "- `lost`: The lost account that you want to recover."] - #[doc = "- `rescuer`: The account trying to rescue the lost account that you want to vouch for."] - #[doc = ""] - #[doc = "The combination of these two parameters must point to an active recovery"] - #[doc = "process."] - pub struct VouchRecovery { - pub lost: vouch_recovery::Lost, - pub rescuer: vouch_recovery::Rescuer, - } - pub mod vouch_recovery { - use super::runtime_types; - pub type Lost = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - pub type Rescuer = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for VouchRecovery { - const PALLET: &'static str = "Recovery"; - const CALL: &'static str = "vouch_recovery"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Allow a successful rescuer to claim their recovered account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_ and must be a \"rescuer\""] - #[doc = "who has successfully completed the account recovery process: collected"] - #[doc = "`threshold` or more vouches, waited `delay_period` blocks since initiation."] - #[doc = ""] - #[doc = "Parameters:"] - #[doc = "- `account`: The lost account that you want to claim has been successfully recovered by"] - #[doc = " you."] - pub struct ClaimRecovery { - pub account: claim_recovery::Account, - } - pub mod claim_recovery { - use super::runtime_types; - pub type Account = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ClaimRecovery { - const PALLET: &'static str = "Recovery"; - const CALL: &'static str = "claim_recovery"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "As the controller of a recoverable account, close an active recovery"] - #[doc = "process for your account."] + #[doc = "As the controller of a recoverable account, close an active recovery"] + #[doc = "process for your account."] #[doc = ""] #[doc = "Payment: By calling this function, the recoverable account will receive"] #[doc = "the recovery deposit `RecoveryDeposit` placed by the rescuer."] @@ -16497,9 +15321,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 62u8, 111u8, 80u8, 232u8, 188u8, 15u8, 202u8, 50u8, 77u8, 223u8, 96u8, - 15u8, 232u8, 213u8, 143u8, 185u8, 200u8, 40u8, 119u8, 120u8, 195u8, - 183u8, 193u8, 129u8, 198u8, 43u8, 220u8, 26u8, 149u8, 14u8, 92u8, 42u8, + 125u8, 10u8, 181u8, 50u8, 177u8, 114u8, 92u8, 100u8, 221u8, 17u8, 19u8, + 106u8, 84u8, 156u8, 189u8, 217u8, 223u8, 233u8, 245u8, 200u8, 8u8, + 24u8, 21u8, 189u8, 205u8, 170u8, 119u8, 109u8, 156u8, 192u8, 139u8, + 202u8, ], ) } @@ -20182,42 +19007,621 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Some account `who` was created with a deposit from `depositor`."] - pub struct Touched { - pub asset_id: touched::AssetId, - pub who: touched::Who, - pub depositor: touched::Depositor, + #[doc = "Some account `who` was created with a deposit from `depositor`."] + pub struct Touched { + pub asset_id: touched::AssetId, + pub who: touched::Who, + pub depositor: touched::Depositor, + } + pub mod touched { + use super::runtime_types; + pub type AssetId = ::core::primitive::u32; + pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Depositor = ::subxt::ext::subxt_core::utils::AccountId32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for Touched { + const PALLET: &'static str = "Assets"; + const EVENT: &'static str = "Touched"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Some account `who` was blocked."] + pub struct Blocked { + pub asset_id: blocked::AssetId, + pub who: blocked::Who, + } + pub mod blocked { + use super::runtime_types; + pub type AssetId = ::core::primitive::u32; + pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for Blocked { + const PALLET: &'static str = "Assets"; + const EVENT: &'static str = "Blocked"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Some assets were deposited (e.g. for transaction fees)."] + pub struct Deposited { + pub asset_id: deposited::AssetId, + pub who: deposited::Who, + pub amount: deposited::Amount, + } + pub mod deposited { + use super::runtime_types; + pub type AssetId = ::core::primitive::u32; + pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Amount = ::core::primitive::u128; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for Deposited { + const PALLET: &'static str = "Assets"; + const EVENT: &'static str = "Deposited"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Some assets were withdrawn from the account (e.g. for transaction fees)."] + pub struct Withdrawn { + pub asset_id: withdrawn::AssetId, + pub who: withdrawn::Who, + pub amount: withdrawn::Amount, + } + pub mod withdrawn { + use super::runtime_types; + pub type AssetId = ::core::primitive::u32; + pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Amount = ::core::primitive::u128; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for Withdrawn { + const PALLET: &'static str = "Assets"; + const EVENT: &'static str = "Withdrawn"; + } + } + pub mod storage { + use super::runtime_types; + pub mod types { + use super::runtime_types; + pub mod asset { + use super::runtime_types; + pub type Asset = runtime_types::pallet_assets::types::AssetDetails< + ::core::primitive::u128, + ::subxt::ext::subxt_core::utils::AccountId32, + ::core::primitive::u128, + >; + pub type Param0 = ::core::primitive::u32; + } + pub mod account { + use super::runtime_types; + pub type Account = runtime_types::pallet_assets::types::AssetAccount< + ::core::primitive::u128, + ::core::primitive::u128, + (), + ::subxt::ext::subxt_core::utils::AccountId32, + >; + pub type Param0 = ::core::primitive::u32; + pub type Param1 = ::subxt::ext::subxt_core::utils::AccountId32; + } + pub mod approvals { + use super::runtime_types; + pub type Approvals = runtime_types::pallet_assets::types::Approval< + ::core::primitive::u128, + ::core::primitive::u128, + >; + pub type Param0 = ::core::primitive::u32; + pub type Param1 = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Param2 = ::subxt::ext::subxt_core::utils::AccountId32; + } + pub mod metadata { + use super::runtime_types; + pub type Metadata = runtime_types::pallet_assets::types::AssetMetadata< + ::core::primitive::u128, + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u8, + >, + >; + pub type Param0 = ::core::primitive::u32; + } + pub mod next_asset_id { + use super::runtime_types; + pub type NextAssetId = ::core::primitive::u32; + } + } + pub struct StorageApi; + impl StorageApi { + #[doc = " Details of an asset."] + pub fn asset_iter( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::asset::Asset, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Asset", + (), + [ + 159u8, 234u8, 177u8, 31u8, 58u8, 51u8, 173u8, 184u8, 250u8, 169u8, + 246u8, 122u8, 54u8, 19u8, 232u8, 60u8, 0u8, 165u8, 12u8, 101u8, 93u8, + 169u8, 23u8, 34u8, 154u8, 44u8, 134u8, 128u8, 97u8, 71u8, 167u8, 224u8, + ], + ) + } + #[doc = " Details of an asset."] + pub fn asset( + &self, + _0: types::asset::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::asset::Param0, + >, + types::asset::Asset, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Asset", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + [ + 159u8, 234u8, 177u8, 31u8, 58u8, 51u8, 173u8, 184u8, 250u8, 169u8, + 246u8, 122u8, 54u8, 19u8, 232u8, 60u8, 0u8, 165u8, 12u8, 101u8, 93u8, + 169u8, 23u8, 34u8, 154u8, 44u8, 134u8, 128u8, 97u8, 71u8, 167u8, 224u8, + ], + ) + } + #[doc = " The holdings of a specific account for a specific asset."] + pub fn account_iter( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::account::Account, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Account", + (), + [ + 188u8, 242u8, 133u8, 64u8, 0u8, 11u8, 57u8, 146u8, 60u8, 137u8, 35u8, + 23u8, 183u8, 200u8, 242u8, 8u8, 94u8, 158u8, 218u8, 13u8, 104u8, 215u8, + 87u8, 86u8, 69u8, 200u8, 11u8, 51u8, 6u8, 65u8, 216u8, 102u8, + ], + ) + } + #[doc = " The holdings of a specific account for a specific asset."] + pub fn account_iter1( + &self, + _0: types::account::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::account::Param0, + >, + types::account::Account, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Account", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + [ + 188u8, 242u8, 133u8, 64u8, 0u8, 11u8, 57u8, 146u8, 60u8, 137u8, 35u8, + 23u8, 183u8, 200u8, 242u8, 8u8, 94u8, 158u8, 218u8, 13u8, 104u8, 215u8, + 87u8, 86u8, 69u8, 200u8, 11u8, 51u8, 6u8, 65u8, 216u8, 102u8, + ], + ) + } + #[doc = " The holdings of a specific account for a specific asset."] + pub fn account( + &self, + _0: types::account::Param0, + _1: types::account::Param1, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ( + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::account::Param0, + >, + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::account::Param1, + >, + ), + types::account::Account, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Account", + ( + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), + ), + [ + 188u8, 242u8, 133u8, 64u8, 0u8, 11u8, 57u8, 146u8, 60u8, 137u8, 35u8, + 23u8, 183u8, 200u8, 242u8, 8u8, 94u8, 158u8, 218u8, 13u8, 104u8, 215u8, + 87u8, 86u8, 69u8, 200u8, 11u8, 51u8, 6u8, 65u8, 216u8, 102u8, + ], + ) + } + #[doc = " Approved balance transfers. First balance is the amount approved for transfer. Second"] + #[doc = " is the amount of `T::Currency` reserved for storing this."] + #[doc = " First key is the asset ID, second key is the owner and third key is the delegate."] + pub fn approvals_iter( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::approvals::Approvals, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Approvals", + (), + [ + 122u8, 92u8, 51u8, 45u8, 200u8, 200u8, 182u8, 208u8, 18u8, 47u8, 139u8, + 68u8, 254u8, 15u8, 152u8, 110u8, 3u8, 138u8, 13u8, 183u8, 5u8, 185u8, + 218u8, 44u8, 93u8, 28u8, 56u8, 189u8, 125u8, 127u8, 123u8, 8u8, + ], + ) + } + #[doc = " Approved balance transfers. First balance is the amount approved for transfer. Second"] + #[doc = " is the amount of `T::Currency` reserved for storing this."] + #[doc = " First key is the asset ID, second key is the owner and third key is the delegate."] + pub fn approvals_iter1( + &self, + _0: types::approvals::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::approvals::Param0, + >, + types::approvals::Approvals, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Approvals", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + [ + 122u8, 92u8, 51u8, 45u8, 200u8, 200u8, 182u8, 208u8, 18u8, 47u8, 139u8, + 68u8, 254u8, 15u8, 152u8, 110u8, 3u8, 138u8, 13u8, 183u8, 5u8, 185u8, + 218u8, 44u8, 93u8, 28u8, 56u8, 189u8, 125u8, 127u8, 123u8, 8u8, + ], + ) + } + #[doc = " Approved balance transfers. First balance is the amount approved for transfer. Second"] + #[doc = " is the amount of `T::Currency` reserved for storing this."] + #[doc = " First key is the asset ID, second key is the owner and third key is the delegate."] + pub fn approvals_iter2( + &self, + _0: types::approvals::Param0, + _1: types::approvals::Param1, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ( + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::approvals::Param0, + >, + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::approvals::Param1, + >, + ), + types::approvals::Approvals, + (), + (), + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Approvals", + ( + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), + ), + [ + 122u8, 92u8, 51u8, 45u8, 200u8, 200u8, 182u8, 208u8, 18u8, 47u8, 139u8, + 68u8, 254u8, 15u8, 152u8, 110u8, 3u8, 138u8, 13u8, 183u8, 5u8, 185u8, + 218u8, 44u8, 93u8, 28u8, 56u8, 189u8, 125u8, 127u8, 123u8, 8u8, + ], + ) + } + #[doc = " Approved balance transfers. First balance is the amount approved for transfer. Second"] + #[doc = " is the amount of `T::Currency` reserved for storing this."] + #[doc = " First key is the asset ID, second key is the owner and third key is the delegate."] + pub fn approvals( + &self, + _0: types::approvals::Param0, + _1: types::approvals::Param1, + _2: types::approvals::Param2, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ( + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::approvals::Param0, + >, + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::approvals::Param1, + >, + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::approvals::Param2, + >, + ), + types::approvals::Approvals, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Approvals", + ( + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_2), + ), + [ + 122u8, 92u8, 51u8, 45u8, 200u8, 200u8, 182u8, 208u8, 18u8, 47u8, 139u8, + 68u8, 254u8, 15u8, 152u8, 110u8, 3u8, 138u8, 13u8, 183u8, 5u8, 185u8, + 218u8, 44u8, 93u8, 28u8, 56u8, 189u8, 125u8, 127u8, 123u8, 8u8, + ], + ) + } + #[doc = " Metadata of an asset."] + pub fn metadata_iter( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::metadata::Metadata, + (), + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Metadata", + (), + [ + 129u8, 202u8, 244u8, 77u8, 55u8, 81u8, 86u8, 106u8, 20u8, 153u8, 209u8, + 69u8, 199u8, 107u8, 111u8, 49u8, 88u8, 157u8, 84u8, 41u8, 198u8, 190u8, + 234u8, 218u8, 68u8, 207u8, 87u8, 217u8, 73u8, 66u8, 211u8, 163u8, + ], + ) + } + #[doc = " Metadata of an asset."] + pub fn metadata( + &self, + _0: types::metadata::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::metadata::Param0, + >, + types::metadata::Metadata, + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "Metadata", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + [ + 129u8, 202u8, 244u8, 77u8, 55u8, 81u8, 86u8, 106u8, 20u8, 153u8, 209u8, + 69u8, 199u8, 107u8, 111u8, 49u8, 88u8, 157u8, 84u8, 41u8, 198u8, 190u8, + 234u8, 218u8, 68u8, 207u8, 87u8, 217u8, 73u8, 66u8, 211u8, 163u8, + ], + ) + } + #[doc = " The asset ID enforced for the next asset creation, if any present. Otherwise, this storage"] + #[doc = " item has no effect."] + #[doc = ""] + #[doc = " This can be useful for setting up constraints for IDs of the new assets. For example, by"] + #[doc = " providing an initial [`NextAssetId`] and using the [`crate::AutoIncAssetId`] callback, an"] + #[doc = " auto-increment model can be applied to all new asset IDs."] + #[doc = ""] + #[doc = " The initial next asset ID can be set using the [`GenesisConfig`] or the"] + #[doc = " [SetNextAssetId](`migration::next_asset_id::SetNextAssetId`) migration."] + pub fn next_asset_id( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::next_asset_id::NextAssetId, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Assets", + "NextAssetId", + (), + [ + 15u8, 61u8, 40u8, 217u8, 236u8, 34u8, 95u8, 53u8, 159u8, 182u8, 70u8, + 251u8, 234u8, 188u8, 115u8, 23u8, 199u8, 118u8, 220u8, 40u8, 147u8, + 174u8, 247u8, 129u8, 246u8, 107u8, 178u8, 43u8, 8u8, 19u8, 74u8, 116u8, + ], + ) + } + } + } + pub mod constants { + use super::runtime_types; + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " Max number of items to destroy per `destroy_accounts` and `destroy_approvals` call."] + #[doc = ""] + #[doc = " Must be configured to result in a weight that makes each call fit in a block."] + pub fn remove_items_limit( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Assets", + "RemoveItemsLimit", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " The basic amount of funds that must be reserved for an asset."] + pub fn asset_deposit( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Assets", + "AssetDeposit", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) + } + #[doc = " The amount of funds that must be reserved for a non-provider asset account to be"] + #[doc = " maintained."] + pub fn asset_account_deposit( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Assets", + "AssetAccountDeposit", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) + } + #[doc = " The basic amount of funds that must be reserved when adding metadata to your asset."] + pub fn metadata_deposit_base( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Assets", + "MetadataDepositBase", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) + } + #[doc = " The additional funds that must be reserved for the number of bytes you store in your"] + #[doc = " metadata."] + pub fn metadata_deposit_per_byte( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Assets", + "MetadataDepositPerByte", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) + } + #[doc = " The amount of funds that must be reserved when creating a new approval."] + pub fn approval_deposit( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Assets", + "ApprovalDeposit", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) + } + #[doc = " The maximum length of a name or symbol stored on-chain."] + pub fn string_limit( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Assets", + "StringLimit", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + } + } + } + pub mod assets_holder { + use super::{root_mod, runtime_types}; + #[doc = "The `Error` enum of this pallet."] + pub type Error = runtime_types::pallet_assets_holder::pallet::Error; + #[doc = "The `Event` enum of this pallet"] + pub type Event = runtime_types::pallet_assets_holder::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "`who`s balance on hold was increased by `amount`."] + pub struct Held { + pub who: held::Who, + pub asset_id: held::AssetId, + pub reason: held::Reason, + pub amount: held::Amount, } - pub mod touched { + pub mod held { use super::runtime_types; - pub type AssetId = ::core::primitive::u32; pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; - pub type Depositor = ::subxt::ext::subxt_core::utils::AccountId32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Touched { - const PALLET: &'static str = "Assets"; - const EVENT: &'static str = "Touched"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Some account `who` was blocked."] - pub struct Blocked { - pub asset_id: blocked::AssetId, - pub who: blocked::Who, - } - pub mod blocked { - use super::runtime_types; pub type AssetId = ::core::primitive::u32; - pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Reason = runtime_types::quantus_runtime::RuntimeHoldReason; + pub type Amount = ::core::primitive::u128; } - impl ::subxt::ext::subxt_core::events::StaticEvent for Blocked { - const PALLET: &'static str = "Assets"; - const EVENT: &'static str = "Blocked"; + impl ::subxt::ext::subxt_core::events::StaticEvent for Held { + const PALLET: &'static str = "AssetsHolder"; + const EVENT: &'static str = "Held"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -20226,21 +19630,23 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Some assets were deposited (e.g. for transaction fees)."] - pub struct Deposited { - pub asset_id: deposited::AssetId, - pub who: deposited::Who, - pub amount: deposited::Amount, + #[doc = "`who`s balance on hold was decreased by `amount`."] + pub struct Released { + pub who: released::Who, + pub asset_id: released::AssetId, + pub reason: released::Reason, + pub amount: released::Amount, } - pub mod deposited { + pub mod released { use super::runtime_types; - pub type AssetId = ::core::primitive::u32; pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; + pub type AssetId = ::core::primitive::u32; + pub type Reason = runtime_types::quantus_runtime::RuntimeHoldReason; pub type Amount = ::core::primitive::u128; } - impl ::subxt::ext::subxt_core::events::StaticEvent for Deposited { - const PALLET: &'static str = "Assets"; - const EVENT: &'static str = "Deposited"; + impl ::subxt::ext::subxt_core::events::StaticEvent for Released { + const PALLET: &'static str = "AssetsHolder"; + const EVENT: &'static str = "Released"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -20249,528 +19655,743 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "Some assets were withdrawn from the account (e.g. for transaction fees)."] - pub struct Withdrawn { - pub asset_id: withdrawn::AssetId, - pub who: withdrawn::Who, - pub amount: withdrawn::Amount, + #[doc = "`who`s balance on hold was burned by `amount`."] + pub struct Burned { + pub who: burned::Who, + pub asset_id: burned::AssetId, + pub reason: burned::Reason, + pub amount: burned::Amount, } - pub mod withdrawn { + pub mod burned { use super::runtime_types; - pub type AssetId = ::core::primitive::u32; pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; + pub type AssetId = ::core::primitive::u32; + pub type Reason = runtime_types::quantus_runtime::RuntimeHoldReason; pub type Amount = ::core::primitive::u128; } - impl ::subxt::ext::subxt_core::events::StaticEvent for Withdrawn { - const PALLET: &'static str = "Assets"; - const EVENT: &'static str = "Withdrawn"; + impl ::subxt::ext::subxt_core::events::StaticEvent for Burned { + const PALLET: &'static str = "AssetsHolder"; + const EVENT: &'static str = "Burned"; } } pub mod storage { use super::runtime_types; pub mod types { use super::runtime_types; - pub mod asset { - use super::runtime_types; - pub type Asset = runtime_types::pallet_assets::types::AssetDetails< - ::core::primitive::u128, - ::subxt::ext::subxt_core::utils::AccountId32, - ::core::primitive::u128, - >; - pub type Param0 = ::core::primitive::u32; - } - pub mod account { + pub mod holds { use super::runtime_types; - pub type Account = runtime_types::pallet_assets::types::AssetAccount< - ::core::primitive::u128, - ::core::primitive::u128, - (), - ::subxt::ext::subxt_core::utils::AccountId32, + pub type Holds = runtime_types::bounded_collections::bounded_vec::BoundedVec< + runtime_types::frame_support::traits::tokens::misc::IdAmount< + runtime_types::quantus_runtime::RuntimeHoldReason, + ::core::primitive::u128, + >, >; pub type Param0 = ::core::primitive::u32; pub type Param1 = ::subxt::ext::subxt_core::utils::AccountId32; } - pub mod approvals { + pub mod balances_on_hold { use super::runtime_types; - pub type Approvals = runtime_types::pallet_assets::types::Approval< - ::core::primitive::u128, - ::core::primitive::u128, - >; + pub type BalancesOnHold = ::core::primitive::u128; pub type Param0 = ::core::primitive::u32; pub type Param1 = ::subxt::ext::subxt_core::utils::AccountId32; - pub type Param2 = ::subxt::ext::subxt_core::utils::AccountId32; - } - pub mod metadata { - use super::runtime_types; - pub type Metadata = runtime_types::pallet_assets::types::AssetMetadata< - ::core::primitive::u128, - runtime_types::bounded_collections::bounded_vec::BoundedVec< - ::core::primitive::u8, - >, - >; - pub type Param0 = ::core::primitive::u32; - } - pub mod next_asset_id { - use super::runtime_types; - pub type NextAssetId = ::core::primitive::u32; } } pub struct StorageApi; impl StorageApi { - #[doc = " Details of an asset."] - pub fn asset_iter( + #[doc = " A map that stores holds applied on an account for a given AssetId."] + pub fn holds_iter( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< (), - types::asset::Asset, - (), + types::holds::Holds, (), ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Asset", - (), - [ - 159u8, 234u8, 177u8, 31u8, 58u8, 51u8, 173u8, 184u8, 250u8, 169u8, - 246u8, 122u8, 54u8, 19u8, 232u8, 60u8, 0u8, 165u8, 12u8, 101u8, 93u8, - 169u8, 23u8, 34u8, 154u8, 44u8, 134u8, 128u8, 97u8, 71u8, 167u8, 224u8, - ], - ) - } - #[doc = " Details of an asset."] - pub fn asset( - &self, - _0: types::asset::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::asset::Param0, - >, - types::asset::Asset, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Asset", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 159u8, 234u8, 177u8, 31u8, 58u8, 51u8, 173u8, 184u8, 250u8, 169u8, - 246u8, 122u8, 54u8, 19u8, 232u8, 60u8, 0u8, 165u8, 12u8, 101u8, 93u8, - 169u8, 23u8, 34u8, 154u8, 44u8, 134u8, 128u8, 97u8, 71u8, 167u8, 224u8, - ], - ) - } - #[doc = " The holdings of a specific account for a specific asset."] - pub fn account_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::account::Account, - (), - (), ::subxt::ext::subxt_core::utils::Yes, > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Account", + "AssetsHolder", + "Holds", (), [ - 188u8, 242u8, 133u8, 64u8, 0u8, 11u8, 57u8, 146u8, 60u8, 137u8, 35u8, - 23u8, 183u8, 200u8, 242u8, 8u8, 94u8, 158u8, 218u8, 13u8, 104u8, 215u8, - 87u8, 86u8, 69u8, 200u8, 11u8, 51u8, 6u8, 65u8, 216u8, 102u8, + 131u8, 85u8, 98u8, 45u8, 101u8, 28u8, 94u8, 4u8, 1u8, 137u8, 126u8, + 129u8, 241u8, 99u8, 206u8, 145u8, 177u8, 135u8, 27u8, 52u8, 122u8, + 94u8, 241u8, 29u8, 253u8, 154u8, 158u8, 229u8, 208u8, 129u8, 29u8, + 41u8, ], ) } - #[doc = " The holdings of a specific account for a specific asset."] - pub fn account_iter1( + #[doc = " A map that stores holds applied on an account for a given AssetId."] + pub fn holds_iter1( &self, - _0: types::account::Param0, + _0: types::holds::Param0, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::account::Param0, + types::holds::Param0, >, - types::account::Account, - (), + types::holds::Holds, (), ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Account", + "AssetsHolder", + "Holds", ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 188u8, 242u8, 133u8, 64u8, 0u8, 11u8, 57u8, 146u8, 60u8, 137u8, 35u8, - 23u8, 183u8, 200u8, 242u8, 8u8, 94u8, 158u8, 218u8, 13u8, 104u8, 215u8, - 87u8, 86u8, 69u8, 200u8, 11u8, 51u8, 6u8, 65u8, 216u8, 102u8, + 131u8, 85u8, 98u8, 45u8, 101u8, 28u8, 94u8, 4u8, 1u8, 137u8, 126u8, + 129u8, 241u8, 99u8, 206u8, 145u8, 177u8, 135u8, 27u8, 52u8, 122u8, + 94u8, 241u8, 29u8, 253u8, 154u8, 158u8, 229u8, 208u8, 129u8, 29u8, + 41u8, ], ) } - #[doc = " The holdings of a specific account for a specific asset."] - pub fn account( + #[doc = " A map that stores holds applied on an account for a given AssetId."] + pub fn holds( &self, - _0: types::account::Param0, - _1: types::account::Param1, + _0: types::holds::Param0, + _1: types::holds::Param1, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< ( ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::account::Param0, + types::holds::Param0, >, ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::account::Param1, + types::holds::Param1, >, ), - types::account::Account, + types::holds::Holds, + ::subxt::ext::subxt_core::utils::Yes, ::subxt::ext::subxt_core::utils::Yes, - (), (), > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Account", + "AssetsHolder", + "Holds", ( ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), ), [ - 188u8, 242u8, 133u8, 64u8, 0u8, 11u8, 57u8, 146u8, 60u8, 137u8, 35u8, - 23u8, 183u8, 200u8, 242u8, 8u8, 94u8, 158u8, 218u8, 13u8, 104u8, 215u8, - 87u8, 86u8, 69u8, 200u8, 11u8, 51u8, 6u8, 65u8, 216u8, 102u8, + 131u8, 85u8, 98u8, 45u8, 101u8, 28u8, 94u8, 4u8, 1u8, 137u8, 126u8, + 129u8, 241u8, 99u8, 206u8, 145u8, 177u8, 135u8, 27u8, 52u8, 122u8, + 94u8, 241u8, 29u8, 253u8, 154u8, 158u8, 229u8, 208u8, 129u8, 29u8, + 41u8, ], ) } - #[doc = " Approved balance transfers. First balance is the amount approved for transfer. Second"] - #[doc = " is the amount of `T::Currency` reserved for storing this."] - #[doc = " First key is the asset ID, second key is the owner and third key is the delegate."] - pub fn approvals_iter( + #[doc = " A map that stores the current total balance on hold for every account on a given AssetId."] + pub fn balances_on_hold_iter( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< (), - types::approvals::Approvals, + types::balances_on_hold::BalancesOnHold, (), (), ::subxt::ext::subxt_core::utils::Yes, > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Approvals", + "AssetsHolder", + "BalancesOnHold", (), [ - 122u8, 92u8, 51u8, 45u8, 200u8, 200u8, 182u8, 208u8, 18u8, 47u8, 139u8, - 68u8, 254u8, 15u8, 152u8, 110u8, 3u8, 138u8, 13u8, 183u8, 5u8, 185u8, - 218u8, 44u8, 93u8, 28u8, 56u8, 189u8, 125u8, 127u8, 123u8, 8u8, + 39u8, 48u8, 137u8, 178u8, 85u8, 119u8, 90u8, 207u8, 72u8, 232u8, 81u8, + 190u8, 234u8, 32u8, 246u8, 199u8, 37u8, 220u8, 0u8, 216u8, 47u8, 241u8, + 9u8, 107u8, 9u8, 130u8, 13u8, 232u8, 142u8, 226u8, 77u8, 179u8, ], ) } - #[doc = " Approved balance transfers. First balance is the amount approved for transfer. Second"] - #[doc = " is the amount of `T::Currency` reserved for storing this."] - #[doc = " First key is the asset ID, second key is the owner and third key is the delegate."] - pub fn approvals_iter1( + #[doc = " A map that stores the current total balance on hold for every account on a given AssetId."] + pub fn balances_on_hold_iter1( &self, - _0: types::approvals::Param0, + _0: types::balances_on_hold::Param0, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::approvals::Param0, + types::balances_on_hold::Param0, >, - types::approvals::Approvals, + types::balances_on_hold::BalancesOnHold, (), (), ::subxt::ext::subxt_core::utils::Yes, > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Approvals", + "AssetsHolder", + "BalancesOnHold", ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 122u8, 92u8, 51u8, 45u8, 200u8, 200u8, 182u8, 208u8, 18u8, 47u8, 139u8, - 68u8, 254u8, 15u8, 152u8, 110u8, 3u8, 138u8, 13u8, 183u8, 5u8, 185u8, - 218u8, 44u8, 93u8, 28u8, 56u8, 189u8, 125u8, 127u8, 123u8, 8u8, + 39u8, 48u8, 137u8, 178u8, 85u8, 119u8, 90u8, 207u8, 72u8, 232u8, 81u8, + 190u8, 234u8, 32u8, 246u8, 199u8, 37u8, 220u8, 0u8, 216u8, 47u8, 241u8, + 9u8, 107u8, 9u8, 130u8, 13u8, 232u8, 142u8, 226u8, 77u8, 179u8, + ], + ) + } + #[doc = " A map that stores the current total balance on hold for every account on a given AssetId."] + pub fn balances_on_hold( + &self, + _0: types::balances_on_hold::Param0, + _1: types::balances_on_hold::Param1, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ( + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::balances_on_hold::Param0, + >, + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::balances_on_hold::Param1, + >, + ), + types::balances_on_hold::BalancesOnHold, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "AssetsHolder", + "BalancesOnHold", + ( + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), + ), + [ + 39u8, 48u8, 137u8, 178u8, 85u8, 119u8, 90u8, 207u8, 72u8, 232u8, 81u8, + 190u8, 234u8, 32u8, 246u8, 199u8, 37u8, 220u8, 0u8, 216u8, 47u8, 241u8, + 9u8, 107u8, 9u8, 130u8, 13u8, 232u8, 142u8, 226u8, 77u8, 179u8, ], ) } - #[doc = " Approved balance transfers. First balance is the amount approved for transfer. Second"] - #[doc = " is the amount of `T::Currency` reserved for storing this."] - #[doc = " First key is the asset ID, second key is the owner and third key is the delegate."] - pub fn approvals_iter2( - &self, - _0: types::approvals::Param0, - _1: types::approvals::Param1, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ( - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::approvals::Param0, - >, - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::approvals::Param1, - >, - ), - types::approvals::Approvals, - (), - (), - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Approvals", - ( - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), - ), - [ - 122u8, 92u8, 51u8, 45u8, 200u8, 200u8, 182u8, 208u8, 18u8, 47u8, 139u8, - 68u8, 254u8, 15u8, 152u8, 110u8, 3u8, 138u8, 13u8, 183u8, 5u8, 185u8, - 218u8, 44u8, 93u8, 28u8, 56u8, 189u8, 125u8, 127u8, 123u8, 8u8, - ], - ) + } + } + } + pub mod multisig { + use super::{root_mod, runtime_types}; + #[doc = "The `Error` enum of this pallet."] + pub type Error = runtime_types::pallet_multisig::pallet::Error; + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::pallet_multisig::pallet::Call; + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + pub mod types { + use super::runtime_types; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Create a new multisig account with deterministic address"] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `signers`: List of accounts that can sign for this multisig"] + #[doc = "- `threshold`: Number of approvals required to execute transactions"] + #[doc = "- `nonce`: User-provided nonce for address uniqueness"] + #[doc = ""] + #[doc = "The multisig address is deterministically derived from:"] + #[doc = "hash(pallet_id || sorted_signers || threshold || nonce)"] + #[doc = ""] + #[doc = "Signers are automatically sorted before hashing, so order doesn't matter."] + #[doc = ""] + #[doc = "Economic costs:"] + #[doc = "- MultisigFee: burned immediately (spam prevention)"] + #[doc = "- MultisigDeposit: reserved until dissolution, then returned to creator (storage bond)"] + pub struct CreateMultisig { + pub signers: create_multisig::Signers, + pub threshold: create_multisig::Threshold, + pub nonce: create_multisig::Nonce, + } + pub mod create_multisig { + use super::runtime_types; + pub type Signers = ::subxt::ext::subxt_core::alloc::vec::Vec< + ::subxt::ext::subxt_core::utils::AccountId32, + >; + pub type Threshold = ::core::primitive::u32; + pub type Nonce = ::core::primitive::u64; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for CreateMultisig { + const PALLET: &'static str = "Multisig"; + const CALL: &'static str = "create_multisig"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Propose a transaction to be executed by the multisig"] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account that will execute the call"] + #[doc = "- `call`: The encoded call to execute"] + #[doc = "- `expiry`: Block number when this proposal expires"] + #[doc = ""] + #[doc = "The proposer must be a signer and must pay:"] + #[doc = "- A deposit (refundable - returned immediately on execution/cancellation)"] + #[doc = "- A fee (non-refundable, burned immediately)"] + #[doc = ""] + #[doc = "**Auto-cleanup:** Before creating a new proposal, ALL proposer's expired"] + #[doc = "proposals are automatically removed. This is the primary cleanup mechanism."] + #[doc = ""] + #[doc = "**For threshold=1:** If the multisig threshold is 1, the proposal executes immediately."] + #[doc = ""] + #[doc = "**Weight:** Charged upfront for worst-case (high-security path with decode)."] + #[doc = "Refunded to actual cost on success based on whether HS path was taken."] + pub struct Propose { + pub multisig_address: propose::MultisigAddress, + pub call: propose::Call, + pub expiry: propose::Expiry, + } + pub mod propose { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Call = + ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>; + pub type Expiry = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Propose { + const PALLET: &'static str = "Multisig"; + const CALL: &'static str = "propose"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Approve a proposed transaction"] + #[doc = ""] + #[doc = "If this approval brings the total approvals to or above the threshold,"] + #[doc = "the proposal status changes to `Approved` and can be executed via `execute()`."] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account"] + #[doc = "- `proposal_id`: ID (nonce) of the proposal to approve"] + #[doc = ""] + #[doc = "Weight: Charges for MAX call size, refunds based on actual"] + pub struct Approve { + pub multisig_address: approve::MultisigAddress, + pub proposal_id: approve::ProposalId, + } + pub mod approve { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Approve { + const PALLET: &'static str = "Multisig"; + const CALL: &'static str = "approve"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Cancel a proposed transaction (only by proposer)"] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account"] + #[doc = "- `proposal_id`: ID (nonce) of the proposal to cancel"] + pub struct Cancel { + pub multisig_address: cancel::MultisigAddress, + pub proposal_id: cancel::ProposalId, + } + pub mod cancel { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Cancel { + const PALLET: &'static str = "Multisig"; + const CALL: &'static str = "cancel"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Remove expired proposals and return deposits to proposers"] + #[doc = ""] + #[doc = "Can only be called by signers of the multisig."] + #[doc = "Only removes Active proposals that have expired (past expiry block)."] + #[doc = "Executed and Cancelled proposals are automatically cleaned up immediately."] + #[doc = ""] + #[doc = "The deposit is always returned to the original proposer, not the caller."] + #[doc = "This allows any signer to help clean up storage even if proposer is inactive."] + pub struct RemoveExpired { + pub multisig_address: remove_expired::MultisigAddress, + pub proposal_id: remove_expired::ProposalId, + } + pub mod remove_expired { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for RemoveExpired { + const PALLET: &'static str = "Multisig"; + const CALL: &'static str = "remove_expired"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Claim all deposits from expired proposals"] + #[doc = ""] + #[doc = "This is a batch operation that removes all expired proposals where:"] + #[doc = "- Caller is the proposer"] + #[doc = "- Proposal is Active and past expiry block"] + #[doc = ""] + #[doc = "Note: Executed and Cancelled proposals are automatically cleaned up immediately,"] + #[doc = "so only Active+Expired proposals need manual cleanup."] + #[doc = ""] + #[doc = "Returns all proposal deposits to the proposer in a single transaction."] + pub struct ClaimDeposits { + pub multisig_address: claim_deposits::MultisigAddress, + } + pub mod claim_deposits { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + } + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ClaimDeposits { + const PALLET: &'static str = "Multisig"; + const CALL: &'static str = "claim_deposits"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Execute an approved proposal"] + #[doc = ""] + #[doc = "Can be called by any signer of the multisig once the proposal has reached"] + #[doc = "the approval threshold (status = Approved). The proposal must not be expired."] + #[doc = ""] + #[doc = "On execution:"] + #[doc = "- The call is decoded and dispatched as the multisig account"] + #[doc = "- Proposal is removed from storage"] + #[doc = "- Deposit is returned to the proposer"] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account"] + #[doc = "- `proposal_id`: ID (nonce) of the proposal to execute"] + pub struct Execute { + pub multisig_address: execute::MultisigAddress, + pub proposal_id: execute::ProposalId, + } + pub mod execute { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; } - #[doc = " Approved balance transfers. First balance is the amount approved for transfer. Second"] - #[doc = " is the amount of `T::Currency` reserved for storing this."] - #[doc = " First key is the asset ID, second key is the owner and third key is the delegate."] - pub fn approvals( - &self, - _0: types::approvals::Param0, - _1: types::approvals::Param1, - _2: types::approvals::Param2, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ( - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::approvals::Param0, - >, - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::approvals::Param1, - >, - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::approvals::Param2, - >, - ), - types::approvals::Approvals, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Approvals", - ( - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_2), - ), - [ - 122u8, 92u8, 51u8, 45u8, 200u8, 200u8, 182u8, 208u8, 18u8, 47u8, 139u8, - 68u8, 254u8, 15u8, 152u8, 110u8, 3u8, 138u8, 13u8, 183u8, 5u8, 185u8, - 218u8, 44u8, 93u8, 28u8, 56u8, 189u8, 125u8, 127u8, 123u8, 8u8, - ], - ) + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Execute { + const PALLET: &'static str = "Multisig"; + const CALL: &'static str = "execute"; } - #[doc = " Metadata of an asset."] - pub fn metadata_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::metadata::Metadata, - (), - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Metadata", - (), - [ - 129u8, 202u8, 244u8, 77u8, 55u8, 81u8, 86u8, 106u8, 20u8, 153u8, 209u8, - 69u8, 199u8, 107u8, 111u8, 49u8, 88u8, 157u8, 84u8, 41u8, 198u8, 190u8, - 234u8, 218u8, 68u8, 207u8, 87u8, 217u8, 73u8, 66u8, 211u8, 163u8, - ], - ) + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "Approve dissolving a multisig account"] + #[doc = ""] + #[doc = "Signers call this to approve dissolving the multisig."] + #[doc = "When threshold is reached, the multisig is automatically dissolved."] + #[doc = ""] + #[doc = "Requirements:"] + #[doc = "- Caller must be a signer"] + #[doc = "- No proposals exist (active, executed, or cancelled) - must be fully cleaned up"] + #[doc = "- Multisig account balance must be zero"] + #[doc = ""] + #[doc = "When threshold is reached:"] + #[doc = "- Deposit is returned to creator"] + #[doc = "- Multisig storage is removed"] + pub struct ApproveDissolve { + pub multisig_address: approve_dissolve::MultisigAddress, } - #[doc = " Metadata of an asset."] - pub fn metadata( - &self, - _0: types::metadata::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::metadata::Param0, - >, - types::metadata::Metadata, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "Metadata", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 129u8, 202u8, 244u8, 77u8, 55u8, 81u8, 86u8, 106u8, 20u8, 153u8, 209u8, - 69u8, 199u8, 107u8, 111u8, 49u8, 88u8, 157u8, 84u8, 41u8, 198u8, 190u8, - 234u8, 218u8, 68u8, 207u8, 87u8, 217u8, 73u8, 66u8, 211u8, 163u8, - ], - ) + pub mod approve_dissolve { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; } - #[doc = " The asset ID enforced for the next asset creation, if any present. Otherwise, this storage"] - #[doc = " item has no effect."] + impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for ApproveDissolve { + const PALLET: &'static str = "Multisig"; + const CALL: &'static str = "approve_dissolve"; + } + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Create a new multisig account with deterministic address"] #[doc = ""] - #[doc = " This can be useful for setting up constraints for IDs of the new assets. For example, by"] - #[doc = " providing an initial [`NextAssetId`] and using the [`crate::AutoIncAssetId`] callback, an"] - #[doc = " auto-increment model can be applied to all new asset IDs."] + #[doc = "Parameters:"] + #[doc = "- `signers`: List of accounts that can sign for this multisig"] + #[doc = "- `threshold`: Number of approvals required to execute transactions"] + #[doc = "- `nonce`: User-provided nonce for address uniqueness"] #[doc = ""] - #[doc = " The initial next asset ID can be set using the [`GenesisConfig`] or the"] - #[doc = " [SetNextAssetId](`migration::next_asset_id::SetNextAssetId`) migration."] - pub fn next_asset_id( + #[doc = "The multisig address is deterministically derived from:"] + #[doc = "hash(pallet_id || sorted_signers || threshold || nonce)"] + #[doc = ""] + #[doc = "Signers are automatically sorted before hashing, so order doesn't matter."] + #[doc = ""] + #[doc = "Economic costs:"] + #[doc = "- MultisigFee: burned immediately (spam prevention)"] + #[doc = "- MultisigDeposit: reserved until dissolution, then returned to creator (storage bond)"] + pub fn create_multisig( &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::next_asset_id::NextAssetId, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Assets", - "NextAssetId", - (), + signers: types::create_multisig::Signers, + threshold: types::create_multisig::Threshold, + nonce: types::create_multisig::Nonce, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Multisig", + "create_multisig", + types::CreateMultisig { signers, threshold, nonce }, [ - 15u8, 61u8, 40u8, 217u8, 236u8, 34u8, 95u8, 53u8, 159u8, 182u8, 70u8, - 251u8, 234u8, 188u8, 115u8, 23u8, 199u8, 118u8, 220u8, 40u8, 147u8, - 174u8, 247u8, 129u8, 246u8, 107u8, 178u8, 43u8, 8u8, 19u8, 74u8, 116u8, + 126u8, 145u8, 23u8, 129u8, 179u8, 174u8, 124u8, 92u8, 17u8, 77u8, 39u8, + 143u8, 138u8, 202u8, 71u8, 46u8, 71u8, 104u8, 68u8, 236u8, 223u8, + 128u8, 124u8, 89u8, 133u8, 103u8, 92u8, 150u8, 75u8, 49u8, 253u8, + 177u8, ], ) } - } - } - pub mod constants { - use super::runtime_types; - pub struct ConstantsApi; - impl ConstantsApi { - #[doc = " Max number of items to destroy per `destroy_accounts` and `destroy_approvals` call."] + #[doc = "Propose a transaction to be executed by the multisig"] #[doc = ""] - #[doc = " Must be configured to result in a weight that makes each call fit in a block."] - pub fn remove_items_limit( + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account that will execute the call"] + #[doc = "- `call`: The encoded call to execute"] + #[doc = "- `expiry`: Block number when this proposal expires"] + #[doc = ""] + #[doc = "The proposer must be a signer and must pay:"] + #[doc = "- A deposit (refundable - returned immediately on execution/cancellation)"] + #[doc = "- A fee (non-refundable, burned immediately)"] + #[doc = ""] + #[doc = "**Auto-cleanup:** Before creating a new proposal, ALL proposer's expired"] + #[doc = "proposals are automatically removed. This is the primary cleanup mechanism."] + #[doc = ""] + #[doc = "**For threshold=1:** If the multisig threshold is 1, the proposal executes immediately."] + #[doc = ""] + #[doc = "**Weight:** Charged upfront for worst-case (high-security path with decode)."] + #[doc = "Refunded to actual cost on success based on whether HS path was taken."] + pub fn propose( &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u32, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Assets", - "RemoveItemsLimit", + multisig_address: types::propose::MultisigAddress, + call: types::propose::Call, + expiry: types::propose::Expiry, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Multisig", + "propose", + types::Propose { multisig_address, call, expiry }, [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, + 131u8, 107u8, 67u8, 245u8, 123u8, 74u8, 248u8, 60u8, 181u8, 88u8, + 135u8, 198u8, 188u8, 160u8, 34u8, 137u8, 7u8, 126u8, 45u8, 169u8, + 212u8, 30u8, 251u8, 147u8, 167u8, 166u8, 76u8, 70u8, 155u8, 222u8, + 70u8, 143u8, ], ) } - #[doc = " The basic amount of funds that must be reserved for an asset."] - pub fn asset_deposit( + #[doc = "Approve a proposed transaction"] + #[doc = ""] + #[doc = "If this approval brings the total approvals to or above the threshold,"] + #[doc = "the proposal status changes to `Approved` and can be executed via `execute()`."] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account"] + #[doc = "- `proposal_id`: ID (nonce) of the proposal to approve"] + #[doc = ""] + #[doc = "Weight: Charges for MAX call size, refunds based on actual"] + pub fn approve( &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u128, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Assets", - "AssetDeposit", + multisig_address: types::approve::MultisigAddress, + proposal_id: types::approve::ProposalId, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Multisig", + "approve", + types::Approve { multisig_address, proposal_id }, [ - 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, - 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, - 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + 9u8, 56u8, 186u8, 135u8, 222u8, 23u8, 37u8, 64u8, 123u8, 199u8, 205u8, + 29u8, 216u8, 128u8, 37u8, 185u8, 170u8, 121u8, 75u8, 100u8, 198u8, + 80u8, 16u8, 249u8, 170u8, 91u8, 162u8, 201u8, 215u8, 81u8, 87u8, 190u8, ], ) } - #[doc = " The amount of funds that must be reserved for a non-provider asset account to be"] - #[doc = " maintained."] - pub fn asset_account_deposit( + #[doc = "Cancel a proposed transaction (only by proposer)"] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account"] + #[doc = "- `proposal_id`: ID (nonce) of the proposal to cancel"] + pub fn cancel( &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u128, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Assets", - "AssetAccountDeposit", + multisig_address: types::cancel::MultisigAddress, + proposal_id: types::cancel::ProposalId, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Multisig", + "cancel", + types::Cancel { multisig_address, proposal_id }, [ - 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, - 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, - 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + 83u8, 189u8, 89u8, 213u8, 70u8, 183u8, 216u8, 57u8, 226u8, 67u8, 212u8, + 60u8, 59u8, 44u8, 49u8, 165u8, 181u8, 189u8, 26u8, 92u8, 49u8, 185u8, + 224u8, 47u8, 81u8, 111u8, 51u8, 142u8, 165u8, 219u8, 103u8, 82u8, ], ) } - #[doc = " The basic amount of funds that must be reserved when adding metadata to your asset."] - pub fn metadata_deposit_base( + #[doc = "Remove expired proposals and return deposits to proposers"] + #[doc = ""] + #[doc = "Can only be called by signers of the multisig."] + #[doc = "Only removes Active proposals that have expired (past expiry block)."] + #[doc = "Executed and Cancelled proposals are automatically cleaned up immediately."] + #[doc = ""] + #[doc = "The deposit is always returned to the original proposer, not the caller."] + #[doc = "This allows any signer to help clean up storage even if proposer is inactive."] + pub fn remove_expired( &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u128, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Assets", - "MetadataDepositBase", + multisig_address: types::remove_expired::MultisigAddress, + proposal_id: types::remove_expired::ProposalId, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Multisig", + "remove_expired", + types::RemoveExpired { multisig_address, proposal_id }, [ - 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, - 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, - 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + 94u8, 78u8, 117u8, 103u8, 202u8, 220u8, 114u8, 15u8, 215u8, 2u8, 39u8, + 23u8, 128u8, 151u8, 103u8, 78u8, 66u8, 116u8, 182u8, 1u8, 28u8, 44u8, + 111u8, 170u8, 201u8, 171u8, 248u8, 36u8, 71u8, 228u8, 85u8, 82u8, ], - ) - } - #[doc = " The additional funds that must be reserved for the number of bytes you store in your"] - #[doc = " metadata."] - pub fn metadata_deposit_per_byte( + ) + } + #[doc = "Claim all deposits from expired proposals"] + #[doc = ""] + #[doc = "This is a batch operation that removes all expired proposals where:"] + #[doc = "- Caller is the proposer"] + #[doc = "- Proposal is Active and past expiry block"] + #[doc = ""] + #[doc = "Note: Executed and Cancelled proposals are automatically cleaned up immediately,"] + #[doc = "so only Active+Expired proposals need manual cleanup."] + #[doc = ""] + #[doc = "Returns all proposal deposits to the proposer in a single transaction."] + pub fn claim_deposits( &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u128, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Assets", - "MetadataDepositPerByte", + multisig_address: types::claim_deposits::MultisigAddress, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Multisig", + "claim_deposits", + types::ClaimDeposits { multisig_address }, [ - 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, - 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, - 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + 59u8, 70u8, 208u8, 192u8, 13u8, 245u8, 227u8, 53u8, 105u8, 236u8, 5u8, + 102u8, 28u8, 173u8, 134u8, 39u8, 125u8, 165u8, 106u8, 119u8, 150u8, + 100u8, 57u8, 209u8, 37u8, 154u8, 51u8, 66u8, 66u8, 110u8, 57u8, 199u8, ], ) } - #[doc = " The amount of funds that must be reserved when creating a new approval."] - pub fn approval_deposit( + #[doc = "Execute an approved proposal"] + #[doc = ""] + #[doc = "Can be called by any signer of the multisig once the proposal has reached"] + #[doc = "the approval threshold (status = Approved). The proposal must not be expired."] + #[doc = ""] + #[doc = "On execution:"] + #[doc = "- The call is decoded and dispatched as the multisig account"] + #[doc = "- Proposal is removed from storage"] + #[doc = "- Deposit is returned to the proposer"] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account"] + #[doc = "- `proposal_id`: ID (nonce) of the proposal to execute"] + pub fn execute( &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u128, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Assets", - "ApprovalDeposit", + multisig_address: types::execute::MultisigAddress, + proposal_id: types::execute::ProposalId, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Multisig", + "execute", + types::Execute { multisig_address, proposal_id }, [ - 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, - 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, - 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + 209u8, 110u8, 225u8, 231u8, 188u8, 230u8, 192u8, 42u8, 43u8, 233u8, + 158u8, 149u8, 58u8, 203u8, 142u8, 44u8, 40u8, 27u8, 211u8, 194u8, 26u8, + 7u8, 7u8, 254u8, 29u8, 245u8, 230u8, 195u8, 82u8, 108u8, 1u8, 27u8, ], ) } - #[doc = " The maximum length of a name or symbol stored on-chain."] - pub fn string_limit( + #[doc = "Approve dissolving a multisig account"] + #[doc = ""] + #[doc = "Signers call this to approve dissolving the multisig."] + #[doc = "When threshold is reached, the multisig is automatically dissolved."] + #[doc = ""] + #[doc = "Requirements:"] + #[doc = "- Caller must be a signer"] + #[doc = "- No proposals exist (active, executed, or cancelled) - must be fully cleaned up"] + #[doc = "- Multisig account balance must be zero"] + #[doc = ""] + #[doc = "When threshold is reached:"] + #[doc = "- Deposit is returned to creator"] + #[doc = "- Multisig storage is removed"] + pub fn approve_dissolve( &self, - ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< - ::core::primitive::u32, - > { - ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( - "Assets", - "StringLimit", + multisig_address: types::approve_dissolve::MultisigAddress, + ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload + { + ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( + "Multisig", + "approve_dissolve", + types::ApproveDissolve { multisig_address }, [ - 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, - 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, - 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, - 145u8, + 156u8, 98u8, 164u8, 184u8, 61u8, 224u8, 117u8, 109u8, 44u8, 173u8, + 59u8, 188u8, 164u8, 233u8, 191u8, 223u8, 240u8, 203u8, 164u8, 113u8, + 184u8, 187u8, 41u8, 154u8, 87u8, 135u8, 229u8, 56u8, 35u8, 196u8, + 136u8, 241u8, ], ) } } } - } - pub mod assets_holder { - use super::{root_mod, runtime_types}; - #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_assets_holder::pallet::Error; #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_assets_holder::pallet::Event; + pub type Event = runtime_types::pallet_multisig::pallet::Event; pub mod events { use super::runtime_types; #[derive( @@ -20780,23 +20401,51 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "`who`s balance on hold was increased by `amount`."] - pub struct Held { - pub who: held::Who, - pub asset_id: held::AssetId, - pub reason: held::Reason, - pub amount: held::Amount, + #[doc = "A new multisig account was created"] + #[doc = "[creator, multisig_address, signers, threshold, nonce]"] + pub struct MultisigCreated { + pub creator: multisig_created::Creator, + pub multisig_address: multisig_created::MultisigAddress, + pub signers: multisig_created::Signers, + pub threshold: multisig_created::Threshold, + pub nonce: multisig_created::Nonce, + } + pub mod multisig_created { + use super::runtime_types; + pub type Creator = ::subxt::ext::subxt_core::utils::AccountId32; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Signers = ::subxt::ext::subxt_core::alloc::vec::Vec< + ::subxt::ext::subxt_core::utils::AccountId32, + >; + pub type Threshold = ::core::primitive::u32; + pub type Nonce = ::core::primitive::u64; } - pub mod held { + impl ::subxt::ext::subxt_core::events::StaticEvent for MultisigCreated { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "MultisigCreated"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A proposal has been created"] + pub struct ProposalCreated { + pub multisig_address: proposal_created::MultisigAddress, + pub proposer: proposal_created::Proposer, + pub proposal_id: proposal_created::ProposalId, + } + pub mod proposal_created { use super::runtime_types; - pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; - pub type AssetId = ::core::primitive::u32; - pub type Reason = runtime_types::quantus_runtime::RuntimeHoldReason; - pub type Amount = ::core::primitive::u128; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Proposer = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; } - impl ::subxt::ext::subxt_core::events::StaticEvent for Held { - const PALLET: &'static str = "AssetsHolder"; - const EVENT: &'static str = "Held"; + impl ::subxt::ext::subxt_core::events::StaticEvent for ProposalCreated { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "ProposalCreated"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -20805,23 +20454,46 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "`who`s balance on hold was decreased by `amount`."] - pub struct Released { - pub who: released::Who, - pub asset_id: released::AssetId, - pub reason: released::Reason, - pub amount: released::Amount, + #[doc = "A proposal has been approved by a signer"] + pub struct ProposalApproved { + pub multisig_address: proposal_approved::MultisigAddress, + pub approver: proposal_approved::Approver, + pub proposal_id: proposal_approved::ProposalId, + pub approvals_count: proposal_approved::ApprovalsCount, + } + pub mod proposal_approved { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Approver = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; + pub type ApprovalsCount = ::core::primitive::u32; } - pub mod released { + impl ::subxt::ext::subxt_core::events::StaticEvent for ProposalApproved { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "ProposalApproved"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A proposal has reached threshold and is ready to execute"] + pub struct ProposalReadyToExecute { + pub multisig_address: proposal_ready_to_execute::MultisigAddress, + pub proposal_id: proposal_ready_to_execute::ProposalId, + pub approvals_count: proposal_ready_to_execute::ApprovalsCount, + } + pub mod proposal_ready_to_execute { use super::runtime_types; - pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; - pub type AssetId = ::core::primitive::u32; - pub type Reason = runtime_types::quantus_runtime::RuntimeHoldReason; - pub type Amount = ::core::primitive::u128; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; + pub type ApprovalsCount = ::core::primitive::u32; } - impl ::subxt::ext::subxt_core::events::StaticEvent for Released { - const PALLET: &'static str = "AssetsHolder"; - const EVENT: &'static str = "Released"; + impl ::subxt::ext::subxt_core::events::StaticEvent for ProposalReadyToExecute { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "ProposalReadyToExecute"; } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -20830,305 +20502,569 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "`who`s balance on hold was burned by `amount`."] - pub struct Burned { - pub who: burned::Who, - pub asset_id: burned::AssetId, - pub reason: burned::Reason, - pub amount: burned::Amount, + #[doc = "A proposal has been executed"] + #[doc = "Contains all data needed for indexing by SubSquid"] + pub struct ProposalExecuted { + pub multisig_address: proposal_executed::MultisigAddress, + pub proposal_id: proposal_executed::ProposalId, + pub proposer: proposal_executed::Proposer, + pub call: proposal_executed::Call, + pub approvers: proposal_executed::Approvers, + pub result: proposal_executed::Result, + } + pub mod proposal_executed { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; + pub type Proposer = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Call = ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>; + pub type Approvers = ::subxt::ext::subxt_core::alloc::vec::Vec< + ::subxt::ext::subxt_core::utils::AccountId32, + >; + pub type Result = + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>; } - pub mod burned { + impl ::subxt::ext::subxt_core::events::StaticEvent for ProposalExecuted { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "ProposalExecuted"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A proposal has been cancelled by the proposer"] + pub struct ProposalCancelled { + pub multisig_address: proposal_cancelled::MultisigAddress, + pub proposer: proposal_cancelled::Proposer, + pub proposal_id: proposal_cancelled::ProposalId, + } + pub mod proposal_cancelled { use super::runtime_types; - pub type Who = ::subxt::ext::subxt_core::utils::AccountId32; - pub type AssetId = ::core::primitive::u32; - pub type Reason = runtime_types::quantus_runtime::RuntimeHoldReason; - pub type Amount = ::core::primitive::u128; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Proposer = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; } - impl ::subxt::ext::subxt_core::events::StaticEvent for Burned { - const PALLET: &'static str = "AssetsHolder"; - const EVENT: &'static str = "Burned"; + impl ::subxt::ext::subxt_core::events::StaticEvent for ProposalCancelled { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "ProposalCancelled"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Expired proposal was removed from storage"] + pub struct ProposalRemoved { + pub multisig_address: proposal_removed::MultisigAddress, + pub proposal_id: proposal_removed::ProposalId, + pub proposer: proposal_removed::Proposer, + pub removed_by: proposal_removed::RemovedBy, + } + pub mod proposal_removed { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ProposalId = ::core::primitive::u32; + pub type Proposer = ::subxt::ext::subxt_core::utils::AccountId32; + pub type RemovedBy = ::subxt::ext::subxt_core::utils::AccountId32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for ProposalRemoved { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "ProposalRemoved"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "Batch deposits claimed"] + pub struct DepositsClaimed { + pub multisig_address: deposits_claimed::MultisigAddress, + pub claimer: deposits_claimed::Claimer, + pub total_returned: deposits_claimed::TotalReturned, + pub proposals_removed: deposits_claimed::ProposalsRemoved, + pub multisig_removed: deposits_claimed::MultisigRemoved, + } + pub mod deposits_claimed { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Claimer = ::subxt::ext::subxt_core::utils::AccountId32; + pub type TotalReturned = ::core::primitive::u128; + pub type ProposalsRemoved = ::core::primitive::u32; + pub type MultisigRemoved = ::core::primitive::bool; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for DepositsClaimed { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "DepositsClaimed"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A signer approved dissolving the multisig"] + pub struct DissolveApproved { + pub multisig_address: dissolve_approved::MultisigAddress, + pub approver: dissolve_approved::Approver, + pub approvals_count: dissolve_approved::ApprovalsCount, + } + pub mod dissolve_approved { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Approver = ::subxt::ext::subxt_core::utils::AccountId32; + pub type ApprovalsCount = ::core::primitive::u32; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for DissolveApproved { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "DissolveApproved"; + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + #[doc = "A multisig account was dissolved (threshold reached)"] + pub struct MultisigDissolved { + pub multisig_address: multisig_dissolved::MultisigAddress, + pub deposit_returned: multisig_dissolved::DepositReturned, + pub approvers: multisig_dissolved::Approvers, + } + pub mod multisig_dissolved { + use super::runtime_types; + pub type MultisigAddress = ::subxt::ext::subxt_core::utils::AccountId32; + pub type DepositReturned = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Approvers = ::subxt::ext::subxt_core::alloc::vec::Vec< + ::subxt::ext::subxt_core::utils::AccountId32, + >; + } + impl ::subxt::ext::subxt_core::events::StaticEvent for MultisigDissolved { + const PALLET: &'static str = "Multisig"; + const EVENT: &'static str = "MultisigDissolved"; } } pub mod storage { use super::runtime_types; pub mod types { use super::runtime_types; - pub mod holds { + pub mod multisigs { use super::runtime_types; - pub type Holds = runtime_types::bounded_collections::bounded_vec::BoundedVec< - runtime_types::frame_support::traits::tokens::misc::IdAmount< - runtime_types::quantus_runtime::RuntimeHoldReason, - ::core::primitive::u128, + pub type Multisigs = runtime_types::pallet_multisig::MultisigData< + ::subxt::ext::subxt_core::utils::AccountId32, + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::subxt::ext::subxt_core::utils::AccountId32, + >, + ::core::primitive::u128, + runtime_types::bounded_collections::bounded_btree_map::BoundedBTreeMap< + ::subxt::ext::subxt_core::utils::AccountId32, + ::core::primitive::u32, >, >; - pub type Param0 = ::core::primitive::u32; - pub type Param1 = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Param0 = ::subxt::ext::subxt_core::utils::AccountId32; } - pub mod balances_on_hold { + pub mod proposals { use super::runtime_types; - pub type BalancesOnHold = ::core::primitive::u128; - pub type Param0 = ::core::primitive::u32; - pub type Param1 = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Proposals = runtime_types::pallet_multisig::ProposalData< + ::subxt::ext::subxt_core::utils::AccountId32, + ::core::primitive::u128, + ::core::primitive::u32, + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u8, + >, + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::subxt::ext::subxt_core::utils::AccountId32, + >, + >; + pub type Param0 = ::subxt::ext::subxt_core::utils::AccountId32; + pub type Param1 = ::core::primitive::u32; + } + pub mod dissolve_approvals { + use super::runtime_types; + pub type DissolveApprovals = + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::subxt::ext::subxt_core::utils::AccountId32, + >; + pub type Param0 = ::subxt::ext::subxt_core::utils::AccountId32; } } pub struct StorageApi; impl StorageApi { - #[doc = " A map that stores holds applied on an account for a given AssetId."] - pub fn holds_iter( + #[doc = " Multisigs stored by their deterministic address"] + pub fn multisigs_iter( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< (), - types::holds::Holds, + types::multisigs::Multisigs, + (), (), ::subxt::ext::subxt_core::utils::Yes, + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Multisig", + "Multisigs", + (), + [ + 81u8, 182u8, 236u8, 127u8, 98u8, 244u8, 6u8, 51u8, 209u8, 6u8, 214u8, + 144u8, 49u8, 117u8, 203u8, 39u8, 180u8, 247u8, 172u8, 228u8, 72u8, + 25u8, 171u8, 55u8, 41u8, 236u8, 14u8, 135u8, 22u8, 6u8, 241u8, 230u8, + ], + ) + } + #[doc = " Multisigs stored by their deterministic address"] + pub fn multisigs( + &self, + _0: types::multisigs::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::multisigs::Param0, + >, + types::multisigs::Multisigs, + ::subxt::ext::subxt_core::utils::Yes, + (), + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Multisig", + "Multisigs", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + [ + 81u8, 182u8, 236u8, 127u8, 98u8, 244u8, 6u8, 51u8, 209u8, 6u8, 214u8, + 144u8, 49u8, 117u8, 203u8, 39u8, 180u8, 247u8, 172u8, 228u8, 72u8, + 25u8, 171u8, 55u8, 41u8, 236u8, 14u8, 135u8, 22u8, 6u8, 241u8, 230u8, + ], + ) + } + #[doc = " Proposals indexed by (multisig_address, proposal_nonce)"] + pub fn proposals_iter( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::proposals::Proposals, + (), + (), ::subxt::ext::subxt_core::utils::Yes, > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "AssetsHolder", - "Holds", + "Multisig", + "Proposals", (), [ - 131u8, 85u8, 98u8, 45u8, 101u8, 28u8, 94u8, 4u8, 1u8, 137u8, 126u8, - 129u8, 241u8, 99u8, 206u8, 145u8, 177u8, 135u8, 27u8, 52u8, 122u8, - 94u8, 241u8, 29u8, 253u8, 154u8, 158u8, 229u8, 208u8, 129u8, 29u8, - 41u8, + 102u8, 10u8, 240u8, 43u8, 229u8, 237u8, 64u8, 243u8, 64u8, 7u8, 59u8, + 83u8, 229u8, 106u8, 209u8, 184u8, 240u8, 116u8, 205u8, 176u8, 4u8, + 247u8, 234u8, 87u8, 177u8, 197u8, 117u8, 38u8, 83u8, 216u8, 218u8, + 67u8, ], ) } - #[doc = " A map that stores holds applied on an account for a given AssetId."] - pub fn holds_iter1( + #[doc = " Proposals indexed by (multisig_address, proposal_nonce)"] + pub fn proposals_iter1( &self, - _0: types::holds::Param0, + _0: types::proposals::Param0, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::holds::Param0, + types::proposals::Param0, >, - types::holds::Holds, + types::proposals::Proposals, + (), (), - ::subxt::ext::subxt_core::utils::Yes, ::subxt::ext::subxt_core::utils::Yes, > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "AssetsHolder", - "Holds", + "Multisig", + "Proposals", ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 131u8, 85u8, 98u8, 45u8, 101u8, 28u8, 94u8, 4u8, 1u8, 137u8, 126u8, - 129u8, 241u8, 99u8, 206u8, 145u8, 177u8, 135u8, 27u8, 52u8, 122u8, - 94u8, 241u8, 29u8, 253u8, 154u8, 158u8, 229u8, 208u8, 129u8, 29u8, - 41u8, + 102u8, 10u8, 240u8, 43u8, 229u8, 237u8, 64u8, 243u8, 64u8, 7u8, 59u8, + 83u8, 229u8, 106u8, 209u8, 184u8, 240u8, 116u8, 205u8, 176u8, 4u8, + 247u8, 234u8, 87u8, 177u8, 197u8, 117u8, 38u8, 83u8, 216u8, 218u8, + 67u8, ], ) } - #[doc = " A map that stores holds applied on an account for a given AssetId."] - pub fn holds( + #[doc = " Proposals indexed by (multisig_address, proposal_nonce)"] + pub fn proposals( &self, - _0: types::holds::Param0, - _1: types::holds::Param1, + _0: types::proposals::Param0, + _1: types::proposals::Param1, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< ( ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::holds::Param0, + types::proposals::Param0, >, ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::holds::Param1, + types::proposals::Param1, >, ), - types::holds::Holds, - ::subxt::ext::subxt_core::utils::Yes, + types::proposals::Proposals, ::subxt::ext::subxt_core::utils::Yes, (), + (), > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "AssetsHolder", - "Holds", + "Multisig", + "Proposals", ( ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), ), [ - 131u8, 85u8, 98u8, 45u8, 101u8, 28u8, 94u8, 4u8, 1u8, 137u8, 126u8, - 129u8, 241u8, 99u8, 206u8, 145u8, 177u8, 135u8, 27u8, 52u8, 122u8, - 94u8, 241u8, 29u8, 253u8, 154u8, 158u8, 229u8, 208u8, 129u8, 29u8, - 41u8, + 102u8, 10u8, 240u8, 43u8, 229u8, 237u8, 64u8, 243u8, 64u8, 7u8, 59u8, + 83u8, 229u8, 106u8, 209u8, 184u8, 240u8, 116u8, 205u8, 176u8, 4u8, + 247u8, 234u8, 87u8, 177u8, 197u8, 117u8, 38u8, 83u8, 216u8, 218u8, + 67u8, ], ) } - #[doc = " A map that stores the current total balance on hold for every account on a given AssetId."] - pub fn balances_on_hold_iter( + #[doc = " Dissolve approvals: tracks which signers approved dissolving the multisig"] + #[doc = " Maps multisig_address -> Vec"] + pub fn dissolve_approvals_iter( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< (), - types::balances_on_hold::BalancesOnHold, + types::dissolve_approvals::DissolveApprovals, (), (), ::subxt::ext::subxt_core::utils::Yes, > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "AssetsHolder", - "BalancesOnHold", + "Multisig", + "DissolveApprovals", (), [ - 39u8, 48u8, 137u8, 178u8, 85u8, 119u8, 90u8, 207u8, 72u8, 232u8, 81u8, - 190u8, 234u8, 32u8, 246u8, 199u8, 37u8, 220u8, 0u8, 216u8, 47u8, 241u8, - 9u8, 107u8, 9u8, 130u8, 13u8, 232u8, 142u8, 226u8, 77u8, 179u8, + 204u8, 17u8, 210u8, 54u8, 125u8, 128u8, 75u8, 21u8, 158u8, 13u8, 205u8, + 89u8, 98u8, 73u8, 141u8, 159u8, 53u8, 129u8, 19u8, 195u8, 2u8, 178u8, + 26u8, 137u8, 206u8, 7u8, 108u8, 196u8, 195u8, 4u8, 54u8, 111u8, ], ) } - #[doc = " A map that stores the current total balance on hold for every account on a given AssetId."] - pub fn balances_on_hold_iter1( + #[doc = " Dissolve approvals: tracks which signers approved dissolving the multisig"] + #[doc = " Maps multisig_address -> Vec"] + pub fn dissolve_approvals( &self, - _0: types::balances_on_hold::Param0, + _0: types::dissolve_approvals::Param0, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::balances_on_hold::Param0, + types::dissolve_approvals::Param0, >, - types::balances_on_hold::BalancesOnHold, + types::dissolve_approvals::DissolveApprovals, + ::subxt::ext::subxt_core::utils::Yes, (), (), - ::subxt::ext::subxt_core::utils::Yes, > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "AssetsHolder", - "BalancesOnHold", + "Multisig", + "DissolveApprovals", ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 39u8, 48u8, 137u8, 178u8, 85u8, 119u8, 90u8, 207u8, 72u8, 232u8, 81u8, - 190u8, 234u8, 32u8, 246u8, 199u8, 37u8, 220u8, 0u8, 216u8, 47u8, 241u8, - 9u8, 107u8, 9u8, 130u8, 13u8, 232u8, 142u8, 226u8, 77u8, 179u8, + 204u8, 17u8, 210u8, 54u8, 125u8, 128u8, 75u8, 21u8, 158u8, 13u8, 205u8, + 89u8, 98u8, 73u8, 141u8, 159u8, 53u8, 129u8, 19u8, 195u8, 2u8, 178u8, + 26u8, 137u8, 206u8, 7u8, 108u8, 196u8, 195u8, 4u8, 54u8, 111u8, ], ) } - #[doc = " A map that stores the current total balance on hold for every account on a given AssetId."] - pub fn balances_on_hold( + } + } + pub mod constants { + use super::runtime_types; + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " Maximum number of signers allowed in a multisig"] + pub fn max_signers( &self, - _0: types::balances_on_hold::Param0, - _1: types::balances_on_hold::Param1, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ( - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::balances_on_hold::Param0, - >, - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::balances_on_hold::Param1, - >, - ), - types::balances_on_hold::BalancesOnHold, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "AssetsHolder", - "BalancesOnHold", - ( - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_1), - ), + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "MaxSigners", [ - 39u8, 48u8, 137u8, 178u8, 85u8, 119u8, 90u8, 207u8, 72u8, 232u8, 81u8, - 190u8, 234u8, 32u8, 246u8, 199u8, 37u8, 220u8, 0u8, 216u8, 47u8, 241u8, - 9u8, 107u8, 9u8, 130u8, 13u8, 232u8, 142u8, 226u8, 77u8, 179u8, + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, ], ) } - } - } - } - pub mod wormhole { - use super::{root_mod, runtime_types}; - #[doc = "The `Error` enum of this pallet."] - pub type Error = runtime_types::pallet_wormhole::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_wormhole::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - pub struct VerifyWormholeProof { - pub proof_bytes: verify_wormhole_proof::ProofBytes, + #[doc = " Maximum total number of proposals in storage per multisig (Active + Executed +"] + #[doc = " Cancelled) This prevents unbounded storage growth and incentivizes cleanup"] + pub fn max_total_proposals_in_storage( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "MaxTotalProposalsInStorage", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) } - pub mod verify_wormhole_proof { - use super::runtime_types; - pub type ProofBytes = - ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>; + #[doc = " Maximum size of an encoded call"] + pub fn max_call_size( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "MaxCallSize", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for VerifyWormholeProof { - const PALLET: &'static str = "Wormhole"; - const CALL: &'static str = "verify_wormhole_proof"; + #[doc = " Fee charged for creating a multisig (non-refundable, burned)"] + pub fn multisig_fee( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "MultisigFee", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Transfer native tokens and store proof for wormhole"] - pub struct TransferNative { - pub dest: transfer_native::Dest, - #[codec(compact)] - pub amount: transfer_native::Amount, + #[doc = " Deposit reserved for creating a multisig (returned when dissolved)."] + #[doc = " Keeps the state clean by incentivizing removal of unused multisigs."] + pub fn multisig_deposit( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "MultisigDeposit", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) } - pub mod transfer_native { - use super::runtime_types; - pub type Dest = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - pub type Amount = ::core::primitive::u128; + #[doc = " Deposit required per proposal (returned on execute or cancel)"] + pub fn proposal_deposit( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "ProposalDeposit", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for TransferNative { - const PALLET: &'static str = "Wormhole"; - const CALL: &'static str = "transfer_native"; + #[doc = " Fee charged for creating a proposal (non-refundable, paid always)"] + pub fn proposal_fee( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "ProposalFee", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Transfer asset tokens and store proof for wormhole"] - pub struct TransferAsset { - pub asset_id: transfer_asset::AssetId, - pub dest: transfer_asset::Dest, - #[codec(compact)] - pub amount: transfer_asset::Amount, + #[doc = " Percentage increase in ProposalFee for each signer in the multisig."] + #[doc = ""] + #[doc = " Formula: `FinalFee = ProposalFee + (ProposalFee * SignerCount * SignerStepFactor)`"] + #[doc = " Example: If Fee=100, Signers=5, Factor=1%, then Extra = 100 * 5 * 0.01 = 5. Total = 105."] + pub fn signer_step_factor( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + runtime_types::sp_arithmetic::per_things::Permill, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "SignerStepFactor", + [ + 65u8, 93u8, 120u8, 165u8, 204u8, 81u8, 159u8, 163u8, 93u8, 135u8, + 114u8, 121u8, 147u8, 35u8, 215u8, 213u8, 4u8, 223u8, 83u8, 37u8, 225u8, + 200u8, 189u8, 156u8, 140u8, 36u8, 58u8, 46u8, 42u8, 232u8, 155u8, 0u8, + ], + ) } - pub mod transfer_asset { - use super::runtime_types; - pub type AssetId = ::core::primitive::u32; - pub type Dest = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - pub type Amount = ::core::primitive::u128; + #[doc = " Pallet ID for generating multisig addresses"] + pub fn pallet_id( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + runtime_types::frame_support::PalletId, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "PalletId", + [ + 56u8, 243u8, 53u8, 83u8, 154u8, 179u8, 170u8, 80u8, 133u8, 173u8, 61u8, + 161u8, 47u8, 225u8, 146u8, 21u8, 50u8, 229u8, 248u8, 27u8, 104u8, 58u8, + 129u8, 197u8, 102u8, 160u8, 168u8, 205u8, 154u8, 42u8, 217u8, 53u8, + ], + ) } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for TransferAsset { - const PALLET: &'static str = "Wormhole"; - const CALL: &'static str = "transfer_asset"; + #[doc = " Maximum duration (in blocks) that a proposal can be set to expire in the future."] + #[doc = " This prevents proposals from being created with extremely far expiry dates"] + #[doc = " that would lock deposits and bloat storage for extended periods."] + #[doc = ""] + #[doc = " Example: If set to 100_000 blocks (~2 weeks at 12s blocks),"] + #[doc = " a proposal created at block 1000 cannot have expiry > 101_000."] + pub fn max_expiry_duration( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Multisig", + "MaxExpiryDuration", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) } + } + } + } + pub mod wormhole { + use super::{root_mod, runtime_types}; + #[doc = "The `Error` enum of this pallet."] + pub type Error = runtime_types::pallet_wormhole::pallet::Error; + #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] + pub type Call = runtime_types::pallet_wormhole::pallet::Call; + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + pub mod types { + use super::runtime_types; #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, @@ -21156,60 +21092,6 @@ pub mod api { } pub struct TransactionApi; impl TransactionApi { - pub fn verify_wormhole_proof( - &self, - proof_bytes: types::verify_wormhole_proof::ProofBytes, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Wormhole", - "verify_wormhole_proof", - types::VerifyWormholeProof { proof_bytes }, - [ - 242u8, 232u8, 238u8, 253u8, 96u8, 217u8, 86u8, 251u8, 216u8, 200u8, - 103u8, 7u8, 182u8, 218u8, 118u8, 149u8, 120u8, 244u8, 124u8, 33u8, - 133u8, 50u8, 150u8, 163u8, 187u8, 19u8, 37u8, 76u8, 73u8, 48u8, 213u8, - 193u8, - ], - ) - } - #[doc = "Transfer native tokens and store proof for wormhole"] - pub fn transfer_native( - &self, - dest: types::transfer_native::Dest, - amount: types::transfer_native::Amount, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Wormhole", - "transfer_native", - types::TransferNative { dest, amount }, - [ - 108u8, 65u8, 158u8, 226u8, 204u8, 38u8, 41u8, 193u8, 72u8, 15u8, 175u8, - 111u8, 213u8, 47u8, 70u8, 113u8, 235u8, 77u8, 160u8, 118u8, 210u8, - 134u8, 44u8, 76u8, 24u8, 231u8, 234u8, 50u8, 44u8, 75u8, 99u8, 215u8, - ], - ) - } - #[doc = "Transfer asset tokens and store proof for wormhole"] - pub fn transfer_asset( - &self, - asset_id: types::transfer_asset::AssetId, - dest: types::transfer_asset::Dest, - amount: types::transfer_asset::Amount, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Wormhole", - "transfer_asset", - types::TransferAsset { asset_id, dest, amount }, - [ - 49u8, 152u8, 37u8, 165u8, 177u8, 50u8, 177u8, 190u8, 98u8, 23u8, 130u8, - 61u8, 91u8, 175u8, 20u8, 208u8, 21u8, 95u8, 21u8, 10u8, 229u8, 132u8, - 118u8, 155u8, 74u8, 212u8, 103u8, 247u8, 138u8, 49u8, 157u8, 214u8, - ], - ) - } #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch"] pub fn verify_aggregated_proof( &self, @@ -21327,6 +21209,7 @@ pub mod api { pub mod transfer_count { use super::runtime_types; pub type TransferCount = ::core::primitive::u64; + pub type Param0 = ::subxt::ext::subxt_core::utils::AccountId32; } } pub struct StorageApi; @@ -21424,24 +21307,49 @@ pub mod api { ) } #[doc = " Transfer count for all wormhole transfers"] - pub fn transfer_count( + pub fn transfer_count_iter( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< (), types::transfer_count::TransferCount, + (), ::subxt::ext::subxt_core::utils::Yes, ::subxt::ext::subxt_core::utils::Yes, - (), > { ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( "Wormhole", "TransferCount", (), [ - 105u8, 10u8, 160u8, 118u8, 193u8, 131u8, 207u8, 188u8, 78u8, 238u8, - 252u8, 99u8, 31u8, 72u8, 159u8, 128u8, 159u8, 215u8, 110u8, 101u8, - 27u8, 132u8, 12u8, 59u8, 182u8, 107u8, 98u8, 77u8, 189u8, 100u8, 51u8, - 209u8, + 155u8, 203u8, 134u8, 227u8, 130u8, 247u8, 25u8, 140u8, 222u8, 140u8, + 171u8, 84u8, 194u8, 43u8, 94u8, 219u8, 28u8, 230u8, 224u8, 180u8, + 153u8, 223u8, 95u8, 3u8, 28u8, 119u8, 58u8, 220u8, 6u8, 146u8, 145u8, + 4u8, + ], + ) + } + #[doc = " Transfer count for all wormhole transfers"] + pub fn transfer_count( + &self, + _0: types::transfer_count::Param0, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + ::subxt::ext::subxt_core::storage::address::StaticStorageKey< + types::transfer_count::Param0, + >, + types::transfer_count::TransferCount, + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Wormhole", + "TransferCount", + ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), + [ + 155u8, 203u8, 134u8, 227u8, 130u8, 247u8, 25u8, 140u8, 222u8, 140u8, + 171u8, 84u8, 194u8, 43u8, 94u8, 219u8, 28u8, 230u8, 224u8, 180u8, + 153u8, 223u8, 95u8, 3u8, 28u8, 119u8, 58u8, 220u8, 6u8, 146u8, 145u8, + 4u8, ], ) } @@ -21468,6 +21376,58 @@ pub mod api { ], ) } + #[doc = " Minimum transfer amount required for wormhole transfers."] + #[doc = " This prevents dust transfers that waste storage."] + pub fn minimum_transfer_amount( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u128, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Wormhole", + "MinimumTransferAmount", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) + } + #[doc = " Volume fee rate in basis points (1 basis point = 0.01%)."] + #[doc = " This must match the fee rate used in proof generation."] + pub fn volume_fee_rate_bps( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + ::core::primitive::u32, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Wormhole", + "VolumeFeeRateBps", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " Proportion of volume fees to burn (not mint). The remainder goes to the block author."] + #[doc = " Example: Permill::from_percent(50) means 50% burned, 50% to miner."] + pub fn volume_fees_burn_rate( + &self, + ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< + runtime_types::sp_arithmetic::per_things::Permill, + > { + ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( + "Wormhole", + "VolumeFeesBurnRate", + [ + 65u8, 93u8, 120u8, 165u8, 204u8, 81u8, 159u8, 163u8, 93u8, 135u8, + 114u8, 121u8, 147u8, 35u8, 215u8, 213u8, 4u8, 223u8, 83u8, 37u8, 225u8, + 200u8, 189u8, 156u8, 140u8, 36u8, 58u8, 46u8, 42u8, 232u8, 155u8, 0u8, + ], + ) + } } } } @@ -21475,6 +21435,23 @@ pub mod api { use super::runtime_types; pub mod bounded_collections { use super::runtime_types; + pub mod bounded_btree_map { + use super::runtime_types; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + pub struct BoundedBTreeMap<_0, _1>( + pub ::subxt::ext::subxt_core::utils::KeyedVec<_0, _1>, + ); + } pub mod bounded_vec { use super::runtime_types; #[derive( @@ -24283,7 +24260,42 @@ pub mod api { } } } - pub mod pallet_merkle_airdrop { + pub mod pallet_mining_rewards { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + #[doc = "The `Event` enum of this pallet"] + pub enum Event { + #[codec(index = 0)] + #[doc = "A miner has been identified for a block"] + MinerRewarded { + miner: ::subxt::ext::subxt_core::utils::AccountId32, + reward: ::core::primitive::u128, + }, + #[codec(index = 1)] + #[doc = "Transaction fees were collected for later distribution"] + FeesCollected { + amount: ::core::primitive::u128, + total: ::core::primitive::u128, + }, + #[codec(index = 2)] + #[doc = "Rewards were sent to Treasury when no miner was specified"] + TreasuryRewarded { reward: ::core::primitive::u128 }, + } + } + } + pub mod pallet_multisig { use super::runtime_types; pub mod pallet { use super::runtime_types; @@ -24301,86 +24313,139 @@ pub mod api { #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] pub enum Call { #[codec(index = 0)] - #[doc = "Create a new airdrop with a Merkle root."] - #[doc = ""] - #[doc = "The Merkle root is a cryptographic hash that represents all valid claims"] - #[doc = "for this airdrop. Users will later provide Merkle proofs to verify their"] - #[doc = "eligibility to claim tokens."] - #[doc = ""] - #[doc = "# Parameters"] - #[doc = ""] - #[doc = "* `origin` - The origin of the call (must be signed)"] - #[doc = "* `merkle_root` - The Merkle root hash representing all valid claims"] - #[doc = "* `vesting_period` - Optional vesting period for the airdrop"] - #[doc = "* `vesting_delay` - Optional delay before vesting starts"] - create_airdrop { - merkle_root: [::core::primitive::u8; 32usize], - vesting_period: ::core::option::Option<::core::primitive::u32>, - vesting_delay: ::core::option::Option<::core::primitive::u32>, + #[doc = "Create a new multisig account with deterministic address"] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `signers`: List of accounts that can sign for this multisig"] + #[doc = "- `threshold`: Number of approvals required to execute transactions"] + #[doc = "- `nonce`: User-provided nonce for address uniqueness"] + #[doc = ""] + #[doc = "The multisig address is deterministically derived from:"] + #[doc = "hash(pallet_id || sorted_signers || threshold || nonce)"] + #[doc = ""] + #[doc = "Signers are automatically sorted before hashing, so order doesn't matter."] + #[doc = ""] + #[doc = "Economic costs:"] + #[doc = "- MultisigFee: burned immediately (spam prevention)"] + #[doc = "- MultisigDeposit: reserved until dissolution, then returned to creator (storage bond)"] + create_multisig { + signers: ::subxt::ext::subxt_core::alloc::vec::Vec< + ::subxt::ext::subxt_core::utils::AccountId32, + >, + threshold: ::core::primitive::u32, + nonce: ::core::primitive::u64, }, #[codec(index = 1)] - #[doc = "Fund an existing airdrop with tokens."] + #[doc = "Propose a transaction to be executed by the multisig"] #[doc = ""] - #[doc = "This function transfers tokens from the caller to the airdrop's account,"] - #[doc = "making them available for users to claim."] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account that will execute the call"] + #[doc = "- `call`: The encoded call to execute"] + #[doc = "- `expiry`: Block number when this proposal expires"] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "The proposer must be a signer and must pay:"] + #[doc = "- A deposit (refundable - returned immediately on execution/cancellation)"] + #[doc = "- A fee (non-refundable, burned immediately)"] #[doc = ""] - #[doc = "* `origin` - The origin of the call (must be signed)"] - #[doc = "* `airdrop_id` - The ID of the airdrop to fund"] - #[doc = "* `amount` - The amount of tokens to add to the airdrop"] + #[doc = "**Auto-cleanup:** Before creating a new proposal, ALL proposer's expired"] + #[doc = "proposals are automatically removed. This is the primary cleanup mechanism."] #[doc = ""] - #[doc = "# Errors"] + #[doc = "**For threshold=1:** If the multisig threshold is 1, the proposal executes immediately."] #[doc = ""] - #[doc = "* `AirdropNotFound` - If the specified airdrop does not exist"] - fund_airdrop { - airdrop_id: ::core::primitive::u32, - amount: ::core::primitive::u128, + #[doc = "**Weight:** Charged upfront for worst-case (high-security path with decode)."] + #[doc = "Refunded to actual cost on success based on whether HS path was taken."] + propose { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + call: ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>, + expiry: ::core::primitive::u32, }, #[codec(index = 2)] - #[doc = "Claim tokens from an airdrop by providing a Merkle proof."] + #[doc = "Approve a proposed transaction"] #[doc = ""] - #[doc = "Users can claim their tokens by providing a proof of their eligibility."] - #[doc = "The proof is verified against the airdrop's Merkle root."] - #[doc = "Anyone can trigger a claim for any eligible recipient."] + #[doc = "If this approval brings the total approvals to or above the threshold,"] + #[doc = "the proposal status changes to `Approved` and can be executed via `execute()`."] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account"] + #[doc = "- `proposal_id`: ID (nonce) of the proposal to approve"] + #[doc = ""] + #[doc = "Weight: Charges for MAX call size, refunds based on actual"] + approve { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, + }, + #[codec(index = 3)] + #[doc = "Cancel a proposed transaction (only by proposer)"] #[doc = ""] - #[doc = "* `origin` - The origin of the call"] - #[doc = "* `airdrop_id` - The ID of the airdrop to claim from"] - #[doc = "* `amount` - The amount of tokens to claim"] - #[doc = "* `merkle_proof` - The Merkle proof verifying eligibility"] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account"] + #[doc = "- `proposal_id`: ID (nonce) of the proposal to cancel"] + cancel { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, + }, + #[codec(index = 4)] + #[doc = "Remove expired proposals and return deposits to proposers"] #[doc = ""] - #[doc = "# Errors"] + #[doc = "Can only be called by signers of the multisig."] + #[doc = "Only removes Active proposals that have expired (past expiry block)."] + #[doc = "Executed and Cancelled proposals are automatically cleaned up immediately."] #[doc = ""] - #[doc = "* `AirdropNotFound` - If the specified airdrop does not exist"] - #[doc = "* `AlreadyClaimed` - If the recipient has already claimed from this airdrop"] - #[doc = "* `InvalidProof` - If the provided Merkle proof is invalid"] - #[doc = "* `InsufficientAirdropBalance` - If the airdrop doesn't have enough tokens"] - claim { - airdrop_id: ::core::primitive::u32, - recipient: ::subxt::ext::subxt_core::utils::AccountId32, - amount: ::core::primitive::u128, - merkle_proof: runtime_types::bounded_collections::bounded_vec::BoundedVec< - [::core::primitive::u8; 32usize], - >, + #[doc = "The deposit is always returned to the original proposer, not the caller."] + #[doc = "This allows any signer to help clean up storage even if proposer is inactive."] + remove_expired { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, }, - #[codec(index = 3)] - #[doc = "Delete an airdrop and reclaim any remaining funds."] + #[codec(index = 5)] + #[doc = "Claim all deposits from expired proposals"] + #[doc = ""] + #[doc = "This is a batch operation that removes all expired proposals where:"] + #[doc = "- Caller is the proposer"] + #[doc = "- Proposal is Active and past expiry block"] #[doc = ""] - #[doc = "This function allows the creator of an airdrop to delete it and reclaim"] - #[doc = "any remaining tokens that haven't been claimed."] + #[doc = "Note: Executed and Cancelled proposals are automatically cleaned up immediately,"] + #[doc = "so only Active+Expired proposals need manual cleanup."] #[doc = ""] - #[doc = "# Parameters"] + #[doc = "Returns all proposal deposits to the proposer in a single transaction."] + claim_deposits { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + }, + #[codec(index = 7)] + #[doc = "Execute an approved proposal"] + #[doc = ""] + #[doc = "Can be called by any signer of the multisig once the proposal has reached"] + #[doc = "the approval threshold (status = Approved). The proposal must not be expired."] + #[doc = ""] + #[doc = "On execution:"] + #[doc = "- The call is decoded and dispatched as the multisig account"] + #[doc = "- Proposal is removed from storage"] + #[doc = "- Deposit is returned to the proposer"] + #[doc = ""] + #[doc = "Parameters:"] + #[doc = "- `multisig_address`: The multisig account"] + #[doc = "- `proposal_id`: ID (nonce) of the proposal to execute"] + execute { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, + }, + #[codec(index = 6)] + #[doc = "Approve dissolving a multisig account"] #[doc = ""] - #[doc = "* `origin` - The origin of the call (must be the airdrop creator)"] - #[doc = "* `airdrop_id` - The ID of the airdrop to delete"] + #[doc = "Signers call this to approve dissolving the multisig."] + #[doc = "When threshold is reached, the multisig is automatically dissolved."] #[doc = ""] - #[doc = "# Errors"] + #[doc = "Requirements:"] + #[doc = "- Caller must be a signer"] + #[doc = "- No proposals exist (active, executed, or cancelled) - must be fully cleaned up"] + #[doc = "- Multisig account balance must be zero"] #[doc = ""] - #[doc = "* `AirdropNotFound` - If the specified airdrop does not exist"] - #[doc = "* `NotAirdropCreator` - If the caller is not the creator of the airdrop"] - delete_airdrop { airdrop_id: ::core::primitive::u32 }, + #[doc = "When threshold is reached:"] + #[doc = "- Deposit is returned to creator"] + #[doc = "- Multisig storage is removed"] + approve_dissolve { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + }, } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -24396,20 +24461,86 @@ pub mod api { #[doc = "The `Error` enum of this pallet."] pub enum Error { #[codec(index = 0)] - #[doc = "The specified airdrop does not exist."] - AirdropNotFound, + #[doc = "Not enough signers provided"] + NotEnoughSigners, #[codec(index = 1)] - #[doc = "The airdrop does not have sufficient balance for this operation."] - InsufficientAirdropBalance, + #[doc = "Threshold must be greater than zero"] + ThresholdZero, #[codec(index = 2)] - #[doc = "The user has already claimed from this airdrop."] - AlreadyClaimed, + #[doc = "Threshold exceeds number of signers"] + ThresholdTooHigh, #[codec(index = 3)] - #[doc = "The provided Merkle proof is invalid."] - InvalidProof, + #[doc = "Too many signers"] + TooManySigners, #[codec(index = 4)] - #[doc = "Only the creator of an airdrop can delete it."] - NotAirdropCreator, + #[doc = "Duplicate signer in list"] + DuplicateSigner, + #[codec(index = 5)] + #[doc = "Multisig already exists"] + MultisigAlreadyExists, + #[codec(index = 6)] + #[doc = "Multisig not found"] + MultisigNotFound, + #[codec(index = 7)] + #[doc = "Caller is not a signer of this multisig"] + NotASigner, + #[codec(index = 8)] + #[doc = "Proposal not found"] + ProposalNotFound, + #[codec(index = 9)] + #[doc = "Caller is not the proposer"] + NotProposer, + #[codec(index = 10)] + #[doc = "Already approved by this signer"] + AlreadyApproved, + #[codec(index = 11)] + #[doc = "Not enough approvals to execute"] + NotEnoughApprovals, + #[codec(index = 12)] + #[doc = "Proposal expiry is in the past"] + ExpiryInPast, + #[codec(index = 13)] + #[doc = "Proposal expiry is too far in the future (exceeds MaxExpiryDuration)"] + ExpiryTooFar, + #[codec(index = 14)] + #[doc = "Proposal has expired"] + ProposalExpired, + #[codec(index = 15)] + #[doc = "Call data too large"] + CallTooLarge, + #[codec(index = 16)] + #[doc = "Failed to decode call data"] + InvalidCall, + #[codec(index = 17)] + #[doc = "Too many total proposals in storage for this multisig (cleanup required)"] + TooManyProposalsInStorage, + #[codec(index = 18)] + #[doc = "This signer has too many proposals in storage (filibuster protection)"] + TooManyProposalsPerSigner, + #[codec(index = 19)] + #[doc = "Insufficient balance for deposit"] + InsufficientBalance, + #[codec(index = 20)] + #[doc = "Proposal has active deposit"] + ProposalHasDeposit, + #[codec(index = 21)] + #[doc = "Proposal has not expired yet"] + ProposalNotExpired, + #[codec(index = 22)] + #[doc = "Proposal is not active (already executed or cancelled)"] + ProposalNotActive, + #[codec(index = 23)] + #[doc = "Proposal has not been approved yet (threshold not reached)"] + ProposalNotApproved, + #[codec(index = 24)] + #[doc = "Cannot dissolve multisig with existing proposals (clear them first)"] + ProposalsExist, + #[codec(index = 25)] + #[doc = "Multisig account must have zero balance before dissolution"] + MultisigAccountNotZero, + #[codec(index = 26)] + #[doc = "Call is not allowed for high-security multisig"] + CallNotAllowedForHighSecurityMultisig, } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -24425,39 +24556,93 @@ pub mod api { #[doc = "The `Event` enum of this pallet"] pub enum Event { #[codec(index = 0)] - #[doc = "A new airdrop has been created."] - #[doc = ""] - #[doc = "Parameters: [airdrop_id, merkle_root]"] - AirdropCreated { - airdrop_id: ::core::primitive::u32, - airdrop_metadata: runtime_types::pallet_merkle_airdrop::AirdropMetadata< - ::core::primitive::u32, - ::core::primitive::u128, + #[doc = "A new multisig account was created"] + #[doc = "[creator, multisig_address, signers, threshold, nonce]"] + MultisigCreated { + creator: ::subxt::ext::subxt_core::utils::AccountId32, + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + signers: ::subxt::ext::subxt_core::alloc::vec::Vec< + ::subxt::ext::subxt_core::utils::AccountId32, + >, + threshold: ::core::primitive::u32, + nonce: ::core::primitive::u64, + }, + #[codec(index = 1)] + #[doc = "A proposal has been created"] + ProposalCreated { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + proposer: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, + }, + #[codec(index = 2)] + #[doc = "A proposal has been approved by a signer"] + ProposalApproved { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + approver: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, + approvals_count: ::core::primitive::u32, + }, + #[codec(index = 3)] + #[doc = "A proposal has reached threshold and is ready to execute"] + ProposalReadyToExecute { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, + approvals_count: ::core::primitive::u32, + }, + #[codec(index = 4)] + #[doc = "A proposal has been executed"] + #[doc = "Contains all data needed for indexing by SubSquid"] + ProposalExecuted { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, + proposer: ::subxt::ext::subxt_core::utils::AccountId32, + call: ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>, + approvers: ::subxt::ext::subxt_core::alloc::vec::Vec< ::subxt::ext::subxt_core::utils::AccountId32, >, + result: + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, + }, + #[codec(index = 5)] + #[doc = "A proposal has been cancelled by the proposer"] + ProposalCancelled { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + proposer: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, + }, + #[codec(index = 6)] + #[doc = "Expired proposal was removed from storage"] + ProposalRemoved { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + proposal_id: ::core::primitive::u32, + proposer: ::subxt::ext::subxt_core::utils::AccountId32, + removed_by: ::subxt::ext::subxt_core::utils::AccountId32, + }, + #[codec(index = 7)] + #[doc = "Batch deposits claimed"] + DepositsClaimed { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + claimer: ::subxt::ext::subxt_core::utils::AccountId32, + total_returned: ::core::primitive::u128, + proposals_removed: ::core::primitive::u32, + multisig_removed: ::core::primitive::bool, }, - #[codec(index = 1)] - #[doc = "An airdrop has been funded with tokens."] - #[doc = ""] - #[doc = "Parameters: [airdrop_id, amount]"] - AirdropFunded { - airdrop_id: ::core::primitive::u32, - amount: ::core::primitive::u128, + #[codec(index = 8)] + #[doc = "A signer approved dissolving the multisig"] + DissolveApproved { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + approver: ::subxt::ext::subxt_core::utils::AccountId32, + approvals_count: ::core::primitive::u32, }, - #[codec(index = 2)] - #[doc = "A user has claimed tokens from an airdrop."] - #[doc = ""] - #[doc = "Parameters: [airdrop_id, account, amount]"] - Claimed { - airdrop_id: ::core::primitive::u32, - account: ::subxt::ext::subxt_core::utils::AccountId32, - amount: ::core::primitive::u128, + #[codec(index = 9)] + #[doc = "A multisig account was dissolved (threshold reached)"] + MultisigDissolved { + multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, + deposit_returned: ::subxt::ext::subxt_core::utils::AccountId32, + approvers: ::subxt::ext::subxt_core::alloc::vec::Vec< + ::subxt::ext::subxt_core::utils::AccountId32, + >, }, - #[codec(index = 3)] - #[doc = "An airdrop has been deleted."] - #[doc = ""] - #[doc = "Parameters: [airdrop_id]"] - AirdropDeleted { airdrop_id: ::core::primitive::u32 }, } } #[derive( @@ -24467,47 +24652,46 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - pub struct AirdropMetadata<_0, _1, _2> { - pub merkle_root: [::core::primitive::u8; 32usize], - pub creator: _2, - pub balance: _1, - pub vesting_period: ::core::option::Option<_0>, - pub vesting_delay: ::core::option::Option<_0>, + pub struct MultisigData<_0, _1, _2, _3> { + pub creator: _0, + pub signers: _1, + pub threshold: ::core::primitive::u32, + pub proposal_nonce: ::core::primitive::u32, + pub deposit: _2, + pub active_proposals: ::core::primitive::u32, + pub proposals_per_signer: _3, } - } - pub mod pallet_mining_rewards { - use super::runtime_types; - pub mod pallet { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "The `Event` enum of this pallet"] - pub enum Event { - #[codec(index = 0)] - #[doc = "A miner has been identified for a block"] - MinerRewarded { - miner: ::subxt::ext::subxt_core::utils::AccountId32, - reward: ::core::primitive::u128, - }, - #[codec(index = 1)] - #[doc = "Transaction fees were collected for later distribution"] - FeesCollected { - amount: ::core::primitive::u128, - total: ::core::primitive::u128, - }, - #[codec(index = 2)] - #[doc = "Rewards were sent to Treasury when no miner was specified"] - TreasuryRewarded { reward: ::core::primitive::u128 }, - } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + pub struct ProposalData<_0, _1, _2, _3, _4> { + pub proposer: _0, + pub call: _3, + pub expiry: _2, + pub approvals: _4, + pub deposit: _1, + pub status: runtime_types::pallet_multisig::ProposalStatus, + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] + #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] + pub enum ProposalStatus { + #[codec(index = 0)] + Active, + #[codec(index = 1)] + Approved, + #[codec(index = 2)] + Executed, + #[codec(index = 3)] + Cancelled, } } pub mod pallet_preimage { @@ -26010,6 +26194,12 @@ pub mod api { ::core::primitive::u64, >, }, + #[codec(index = 7)] + #[doc = "Allows the guardian (interceptor) to recover all funds from a high security"] + #[doc = "account by transferring the entire balance to themselves."] + #[doc = ""] + #[doc = "This is an emergency function for when the high security account may be compromised."] + recover_funds { account: ::subxt::ext::subxt_core::utils::AccountId32 }, } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -26115,14 +26305,12 @@ pub mod api { }, #[codec(index = 2)] #[doc = "A scheduled transaction has been successfully cancelled by the owner."] - #[doc = "[who, tx_id]"] TransactionCancelled { who: ::subxt::ext::subxt_core::utils::AccountId32, tx_id: ::subxt::ext::subxt_core::utils::H256, }, #[codec(index = 3)] #[doc = "A scheduled transaction was executed by the scheduler."] - #[doc = "[tx_id, dispatch_result]"] TransactionExecuted { tx_id: ::subxt::ext::subxt_core::utils::H256, result: ::core::result::Result< @@ -26132,6 +26320,12 @@ pub mod api { >, >, }, + #[codec(index = 4)] + #[doc = "Funds were recovered from a high security account by its guardian."] + FundsRecovered { + account: ::subxt::ext::subxt_core::utils::AccountId32, + guardian: ::subxt::ext::subxt_core::utils::AccountId32, + }, } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -27366,240 +27560,6 @@ pub mod api { } } } - pub mod pallet_vesting { - use super::runtime_types; - pub mod pallet { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub enum Call { - #[codec(index = 0)] - #[doc = "Unlock any vested funds of the sender account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_ and the sender must have funds still"] - #[doc = "locked under this pallet."] - #[doc = ""] - #[doc = "Emits either `VestingCompleted` or `VestingUpdated`."] - #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - vest, - #[codec(index = 1)] - #[doc = "Unlock any vested funds of a `target` account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - #[doc = ""] - #[doc = "- `target`: The account whose vested funds should be unlocked. Must have funds still"] - #[doc = "locked under this pallet."] - #[doc = ""] - #[doc = "Emits either `VestingCompleted` or `VestingUpdated`."] - #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - vest_other { - target: ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >, - }, - #[codec(index = 2)] - #[doc = "Create a vested transfer."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - #[doc = ""] - #[doc = "- `target`: The account receiving the vested funds."] - #[doc = "- `schedule`: The vesting schedule attached to the transfer."] - #[doc = ""] - #[doc = "Emits `VestingCreated`."] - #[doc = ""] - #[doc = "NOTE: This will unlock all schedules through the current block."] - #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - vested_transfer { - target: ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >, - schedule: runtime_types::pallet_vesting::vesting_info::VestingInfo< - ::core::primitive::u128, - ::core::primitive::u32, - >, - }, - #[codec(index = 3)] - #[doc = "Force a vested transfer."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Root_."] - #[doc = ""] - #[doc = "- `source`: The account whose funds should be transferred."] - #[doc = "- `target`: The account that should be transferred the vested funds."] - #[doc = "- `schedule`: The vesting schedule attached to the transfer."] - #[doc = ""] - #[doc = "Emits `VestingCreated`."] - #[doc = ""] - #[doc = "NOTE: This will unlock all schedules through the current block."] - #[doc = ""] - #[doc = "## Complexity"] - #[doc = "- `O(1)`."] - force_vested_transfer { - source: ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >, - target: ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >, - schedule: runtime_types::pallet_vesting::vesting_info::VestingInfo< - ::core::primitive::u128, - ::core::primitive::u32, - >, - }, - #[codec(index = 4)] - #[doc = "Merge two vesting schedules together, creating a new vesting schedule that unlocks over"] - #[doc = "the highest possible start and end blocks. If both schedules have already started the"] - #[doc = "current block will be used as the schedule start; with the caveat that if one schedule"] - #[doc = "is finished by the current block, the other will be treated as the new merged schedule,"] - #[doc = "unmodified."] - #[doc = ""] - #[doc = "NOTE: If `schedule1_index == schedule2_index` this is a no-op."] - #[doc = "NOTE: This will unlock all schedules through the current block prior to merging."] - #[doc = "NOTE: If both schedules have ended by the current block, no new schedule will be created"] - #[doc = "and both will be removed."] - #[doc = ""] - #[doc = "Merged schedule attributes:"] - #[doc = "- `starting_block`: `MAX(schedule1.starting_block, scheduled2.starting_block,"] - #[doc = " current_block)`."] - #[doc = "- `ending_block`: `MAX(schedule1.ending_block, schedule2.ending_block)`."] - #[doc = "- `locked`: `schedule1.locked_at(current_block) + schedule2.locked_at(current_block)`."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - #[doc = ""] - #[doc = "- `schedule1_index`: index of the first schedule to merge."] - #[doc = "- `schedule2_index`: index of the second schedule to merge."] - merge_schedules { - schedule1_index: ::core::primitive::u32, - schedule2_index: ::core::primitive::u32, - }, - #[codec(index = 5)] - #[doc = "Force remove a vesting schedule"] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Root_."] - #[doc = ""] - #[doc = "- `target`: An account that has a vesting schedule"] - #[doc = "- `schedule_index`: The vesting schedule index that should be removed"] - force_remove_vesting_schedule { - target: ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >, - schedule_index: ::core::primitive::u32, - }, - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Error for the vesting pallet."] - pub enum Error { - #[codec(index = 0)] - #[doc = "The account given is not vesting."] - NotVesting, - #[codec(index = 1)] - #[doc = "The account already has `MaxVestingSchedules` count of schedules and thus"] - #[doc = "cannot add another one. Consider merging existing schedules in order to add another."] - AtMaxVestingSchedules, - #[codec(index = 2)] - #[doc = "Amount being transferred is too low to create a vesting schedule."] - AmountLow, - #[codec(index = 3)] - #[doc = "An index was out of bounds of the vesting schedules."] - ScheduleIndexOutOfBounds, - #[codec(index = 4)] - #[doc = "Failed to create a new schedule because some parameter was invalid."] - InvalidScheduleParams, - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "The `Event` enum of this pallet"] - pub enum Event { - #[codec(index = 0)] - #[doc = "A vesting schedule has been created."] - VestingCreated { - account: ::subxt::ext::subxt_core::utils::AccountId32, - schedule_index: ::core::primitive::u32, - }, - #[codec(index = 1)] - #[doc = "The amount vested has been updated. This could indicate a change in funds available."] - #[doc = "The balance given is the amount which is left unvested (and thus locked)."] - VestingUpdated { - account: ::subxt::ext::subxt_core::utils::AccountId32, - unvested: ::core::primitive::u128, - }, - #[codec(index = 2)] - #[doc = "An \\[account\\] has become fully vested."] - VestingCompleted { account: ::subxt::ext::subxt_core::utils::AccountId32 }, - } - } - pub mod vesting_info { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - pub struct VestingInfo<_0, _1> { - pub locked: _0, - pub per_block: _0, - pub starting_block: _1, - } - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - pub enum Releases { - #[codec(index = 0)] - V0, - #[codec(index = 1)] - V1, - } - } pub mod pallet_wormhole { use super::runtime_types; pub mod pallet { @@ -27617,33 +27577,7 @@ pub mod api { )] #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] pub enum Call { - #[codec(index = 0)] - verify_wormhole_proof { - proof_bytes: - ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>, - }, - #[codec(index = 1)] - #[doc = "Transfer native tokens and store proof for wormhole"] - transfer_native { - dest: ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >, - #[codec(compact)] - amount: ::core::primitive::u128, - }, #[codec(index = 2)] - #[doc = "Transfer asset tokens and store proof for wormhole"] - transfer_asset { - asset_id: ::core::primitive::u32, - dest: ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >, - #[codec(compact)] - amount: ::core::primitive::u128, - }, - #[codec(index = 3)] #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch"] verify_aggregated_proof { proof_bytes: @@ -27684,17 +27618,19 @@ pub mod api { #[codec(index = 9)] InvalidBlockNumber, #[codec(index = 10)] - AssetNotFound, + AggregatedVerifierNotAvailable, #[codec(index = 11)] - SelfTransfer, + AggregatedProofDeserializationFailed, #[codec(index = 12)] - AggregatedVerifierNotAvailable, + AggregatedVerificationFailed, #[codec(index = 13)] - AggregatedProofDeserializationFailed, + InvalidAggregatedPublicInputs, #[codec(index = 14)] - AggregatedVerificationFailed, + #[doc = "The volume fee rate in the proof doesn't match the configured rate"] + InvalidVolumeFeeRate, #[codec(index = 15)] - InvalidAggregatedPublicInputs, + #[doc = "Transfer amount is below the minimum required"] + TransferAmountBelowMinimum, } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, @@ -27943,8 +27879,6 @@ pub mod api { Balances(runtime_types::pallet_balances::pallet::Call), #[codec(index = 4)] Sudo(runtime_types::pallet_sudo::pallet::Call), - #[codec(index = 8)] - Vesting(runtime_types::pallet_vesting::pallet::Call), #[codec(index = 9)] Preimage(runtime_types::pallet_preimage::pallet::Call), #[codec(index = 10)] @@ -27961,8 +27895,6 @@ pub mod api { TechCollective(runtime_types::pallet_ranked_collective::pallet::Call), #[codec(index = 16)] TechReferenda(runtime_types::pallet_referenda::pallet::Call), - #[codec(index = 17)] - MerkleAirdrop(runtime_types::pallet_merkle_airdrop::pallet::Call), #[codec(index = 18)] TreasuryPallet(runtime_types::pallet_treasury::pallet::Call), #[codec(index = 20)] @@ -27970,6 +27902,8 @@ pub mod api { #[codec(index = 21)] Assets(runtime_types::pallet_assets::pallet::Call), #[codec(index = 23)] + Multisig(runtime_types::pallet_multisig::pallet::Call), + #[codec(index = 24)] Wormhole(runtime_types::pallet_wormhole::pallet::Call), } #[derive( @@ -27986,8 +27920,6 @@ pub mod api { Balances(runtime_types::pallet_balances::pallet::Error), #[codec(index = 4)] Sudo(runtime_types::pallet_sudo::pallet::Error), - #[codec(index = 8)] - Vesting(runtime_types::pallet_vesting::pallet::Error), #[codec(index = 9)] Preimage(runtime_types::pallet_preimage::pallet::Error), #[codec(index = 10)] @@ -28004,8 +27936,6 @@ pub mod api { TechCollective(runtime_types::pallet_ranked_collective::pallet::Error), #[codec(index = 16)] TechReferenda(runtime_types::pallet_referenda::pallet::Error), - #[codec(index = 17)] - MerkleAirdrop(runtime_types::pallet_merkle_airdrop::pallet::Error), #[codec(index = 18)] TreasuryPallet(runtime_types::pallet_treasury::pallet::Error), #[codec(index = 20)] @@ -28015,6 +27945,8 @@ pub mod api { #[codec(index = 22)] AssetsHolder(runtime_types::pallet_assets_holder::pallet::Error), #[codec(index = 23)] + Multisig(runtime_types::pallet_multisig::pallet::Error), + #[codec(index = 24)] Wormhole(runtime_types::pallet_wormhole::pallet::Error), } #[derive( @@ -28037,8 +27969,6 @@ pub mod api { QPoW(runtime_types::pallet_qpow::pallet::Event), #[codec(index = 7)] MiningRewards(runtime_types::pallet_mining_rewards::pallet::Event), - #[codec(index = 8)] - Vesting(runtime_types::pallet_vesting::pallet::Event), #[codec(index = 9)] Preimage(runtime_types::pallet_preimage::pallet::Event), #[codec(index = 10)] @@ -28055,8 +27985,6 @@ pub mod api { TechCollective(runtime_types::pallet_ranked_collective::pallet::Event), #[codec(index = 16)] TechReferenda(runtime_types::pallet_referenda::pallet::Event2), - #[codec(index = 17)] - MerkleAirdrop(runtime_types::pallet_merkle_airdrop::pallet::Event), #[codec(index = 18)] TreasuryPallet(runtime_types::pallet_treasury::pallet::Event), #[codec(index = 20)] @@ -28066,6 +27994,8 @@ pub mod api { #[codec(index = 22)] AssetsHolder(runtime_types::pallet_assets_holder::pallet::Event), #[codec(index = 23)] + Multisig(runtime_types::pallet_multisig::pallet::Event), + #[codec(index = 24)] Wormhole(runtime_types::pallet_wormhole::pallet::Event), } #[derive( diff --git a/src/quantus_metadata.scale b/src/quantus_metadata.scale index a4a9a4e257c4ecd9fdeffc1f89e98c45c2d1744f..f55447cfe4fd2a7edb00938b85e0300a619dbb4e 100644 GIT binary patch delta 21301 zcmcJ14|r77weMMbPDla)CX$c|1UV5R8AxJ+iG&z10fM9w2qF9vAxttSWMncE<`0lQ z=|KCSMWKQR?tZp%uiT0iZ>iEq2NbHbdaqb$p~YLZsQ9k7TBRSh(pRt4zTe*GoS8|0 zUT?qm{33H^pS{;!d;Q;QuRUiT8T{da!GpT>h{t*I(4dbTW8WdlY3}lbb%k>Db$TGu zN@{~bu1K)Q*AdP(vego5?whVoqAaaBr2D!(t94a*+W1adIXz>XOS^?$G}J*iJ6@(u zMp^n;WA30)>NcY9@fTjE(Z-fRH?w`jhi9@e#w&vg*?!{l#q;2FjSd-;(r4aK-5Sz8 z;b^G0+2i-?5mh;C97``}M~OENW;q7S$fuW#f{e*@(wLtyskSNVkNCpA)vEG3(S1E~ zOk20rSX0v=R#4j#4Mcq1`gA2v(Ut^5-CaRHaDLO+k}*zoDauk~^NifS6B#eNjGl47 z$12*!-$qA_cZ$XuPlbjWKOR3J@ol)_D!Q4D87FSeqZf=NMT^YmF)vWv{GNy}7^rRa zgxAdTh{?#+qlbJ!uYeRtjOn_0Y2x|yo7X3veG_^U&!0``OFaKu@hZ$->|URFOi|Q~ zBTnT7;|ce8dXazpEamt8#{E8{mwEOD5chW_Ep*D5R=S$b7*D^LYt&WT)OWu0H*7$o zo3`}bTTx52#n@LlweP~@9P802s|?A;xcQ1d=OvxC#0z!W%F<6MN}8&iG0r|R()f1u z$h33n9NK97u-Z+VjSJP&=$vum)UiWnxfb?@BYL;0yhaBNs=LQ{eCk-o`*c)3kFP1D zj|^x1O5?Gb0?IT_)bylE(NJS}eVZ|=wouI_Ys9x}HFXR@HUy~A(=@dr@n%|yI*sTZ z`DViOTh)4^SLK&yrRPfe z|ENA^NK(F{0=Yu_dx>^!q3V@OxOc_~Ay}{VZJzO;MCXnBX4TWXeLtG@d0OsyMPV0| z3xb!`)ylj0R;|3>clJvUIY1fjycu-KIP_ze@%+3&bfxd#=5>+TFv#iE!;zGCMxgm0 z`t>bZFwE-PH@9WA!+giTnN8{ZTkC0<@y?U+um8wX_@-|KlJBU`|(RC0}PuDzS`4NqjTggQT=o|_V_ zfMOg72OUS~4F6Fp-DFIQjO+LEjmX{CfBC0qwN$_yW9GV%68epO8`izatj9?2^Gv=U zVcdD&$>MxcU8eS{YAYS14ClOHKnG2n3xnM-G*Db1K8A$G<{9%h=2M|@V(YlR?HlJg zhMl6UXvJ*`IqlVt>l?Cp4YRs@>ub%7ii{7pjKxaDno74CRM>Z7Yb}!vmB!?4f0R$- z25X(5U%RJcjY-4k{l9ml4()sVn`x9$C`fotDKh#VoJ4Np?FUP#)EK&RJaZFYdq261 zyLL9C<&m9VWfdgMO1?35*95@v>?)FGrI@Pvp57H2M5p@Z{xs7;Q~OH4{m(>I#+gR~ zG}X9cZxK!7ZCf$o{=I_>v{_+2($?i$-PIP>JE9?9q&I_vn0b1of$jVG-bD`e5`9w3 zFMOTg6TVYzY~0s6pyjWRrCXG5{^w=X@8$V^->Qv7SEFeE+~JiWy(73z54Ckh1KzO8 zFZd}xmhLR2dcQxoKCDH$bZvFi6Y}~z0j<~`1S`T#eipe^JGtoMOA#Ht^9+0s5&8pe6c6)lYc3tZTcJ}}| zUs(4Vhkkx1)f>)dNAv0DDBXBtzs4Gf|8*ISqDEf6gtWdXkKaQhPf_Jezb71?-&xyQ zqBX){WkiC~!ekY91Ow}Q5{CtSr@wnz1-HNby|C~k!=G|Vea-8;TpWz(3P1A)$}!d+?O{#k>tSX) z%t{9IW&x1jGI3EqwK{c`TEQVV`NAf*J=Nq+-D^zQ2e0z)q<=1a~M%2*v ztMhvqUE#ZeG#)R${dTFU6ZIGmp2;)L>>AYf!P^gJl5TwRdJ*~fun<)3p$~475L|;S zb5Iu=*Y~FnmY7KAXN2@{M^q2V74&`m!&?c4`?-%aEad!0G1KJd^@T5;AK1Td?H_(` z8Qi}0pM2MTyzNhy?LjmDvxKO-ujjKWbwYPP!e6?I@Ruav*BYn(T0srGa0a>3b3EQ| zUqIq@xQbdFRy%*xL4(W{@#h^hj;_Stb%92nbYjfxn-`y(N$H6%Ylcu+;>)3- zv;*`MQ{`v1>jAyf*WvSodgXl5#R2e^;q*(ZlZ*EhlF3(>{hDXfcP)Uf3|GVhRWseG z-CeaXiAnjNxS)Mat(0jA zh6qu>zw}C~Ob{*cIxilbLND65rO4A@4PHcF?TP3@3i9F)O{HI4qZ@zZcFO8M(JQyp zX?uO~r>4_vdsuu}9o>L8amd*#c4JbM^5WVo+J3F}cN(a{f|w$DdGY0Q2qw~0k<y7j)M_rV%Y6omuT;_M@Ot>Ay6AEdy9oP~@^u)F%iwdyg3Fx7))c%+gA;hhd zv0n=W;bhA3?Y2rqsl6~$4uii6=<79mPn2*R>wS?f&=4*UT=In@z7Eaf^}@o0m6B#p z2wNDu3fFv6s;#nSTUDdYMMo{zX#)`+)Dw$n9dKWwlXO@S;nM8sh7!g{x&RiNE-xU= zi*~o`Aqk@g9&4S)ABLk{8-<(n3je5YK%5YPs}!!(BVADV9AL<`Vf>=79x4?BeO?R@ ztub9rYay>i1HQFU*a)oSd@KCBjfuTF;cfdZ8+7hPOUSnl0ELIIIgkBsSFyzxpI5u@ zJ}n#!MRaeQMG4W8SX4}WljymXB3fv2M)Sb!d!mtGw+ED!Q?>=VhdX3f|4F!O)FV@|yBY=tM zSVnQU$J4F#gyha05rlgg=x>jjrS}BGzDNz|4I+xwihZ$P^Fo<}{-}sJN<^d)K!=D4 z91M}dhd87-jJOD!eXTth@VX1Y0zlKVs4iwxxXqRyDsQc+sW-!-Mz0myR#U-Zy`wf- zEq2EGh8|z2*GaQx_=6p5OqrM+4Ar*c<(xCkCTvJ)v1=Dr|iuklfA~*{QsS`~}S&ix7%qnw5=qOjD z1xzuwf;WhqNiUC>154M#%J&2=78OH~QYaRd=aG5@Y48NRW@C@1x26cosfUb8{%OS_ zU4)~acE7HbYN43TEMJNsAb2zv1E$^r_3Y67en=uD;%Nb@Q`fa($ZTm6R7pahl3?6Q zAx)fE4>2z7@avvHw5Mj`L~VvC!BQ|F!ZFLj*efj2>gUc)tZYKqTCum3>>dbruhNc? z-i=7zTLu<^TKIz?0toU;px) zy%sPlq7!YBYv?!!NsI&$qg`*uEFjd$gAaWNCkQl5yq|I4q zf%1S9o;7-)tiU4;rk+7{_Ufd@#e}IFsB$GXt=oKF%RjK<4fQ4jFw7D>pp>+;NZ_p+Tm*#1Yfp3!L2~w9#C6jx?L|{xf;)z7Vn&91PT@GAj zVd7mS1zq@$RNY?Z^9YTS%qe!SD(k1)PYh6P!T<1ebo({*O`!yOHO`WP-=VvO59)`e z;EqWk<$a6)7Wc!F>rM4bP1O(kzO0wPNSd3%Sb}#ZZ(XLk4P?_7^n-Lozk6&=1s`hS+)Op)JSPK#X zfiQli53-G(lp1@*VdV&D1Z@$7&|{J*&>qml_Rkh;Z9OT=rum|?iFsJ7M_d7+wbw4> z8!n*BgEnhb8r(lL)U@hayYN!(GB-7tGU=5VntbxdFm)2r)s{^fFZ7A_^fxnw)Cv=4 z8+D;{{`H<-5e+4suaM7R$hX=TfEwA$FF~{sk)kUcksb?`RRNR)AhQ~tfK3RYqg}ec z$26b<1KWv<073J0CSVHdh)E<}%Br!C_jR{fsD;(P&EQxBK0dAZF(eaw$d14@+5^pe ziA~W2jg+A#x&mVuzDP%x7DTFCx+g3PoUr*MfL%3Qn8=V`v#L~^DV86KCB20VNkT9X z%`$=j%`k_>Y#~!u@l>g&c}PgqXxC!w7vyWKKVwVIiHJ@}n>q2M2I=rqWh9^jbT`~7 z5VTxd8H{g>WW10Ao7Z@spe0zDv{rBsz5u8f7XBAuK#CPFE3gdb-)Vr-D|;+rK*()_ zn8Y3-uFyS^auU>s*2Q|!F(GjSG!K*zd9OsMgB2n21%o{uUAnhQ`U%^mpquTh5o}7A zF-@}_gSO3j#KfD#|%~gCnUb_IfcH)>x5+HKiDwO4PEUw8YF~ z+8mbjl0sm{WQmFJqW`|hUWFIzZ83L>-N>tkYrLifh(Q?!hR^i~nCAsk%(A{g>|BdY z16N{G%3C5r7}KpmmfZ-aZAhI_u`Nv6?njdQC|g3Tv@ZYbG7VmWR7+6ly6z%tHc45z zmZ(@8tVqfPww3mUji0TVN4@+|6Ov~tA3L8ai17vU$)Jt=z4=tgHWTl8ipqI)Gu?n= zJCXJ6Y^M3NO(x;_ubXKIGOMFQi*& z7k_mjjYZStg*0Vo^=y$iZ!xpz##!f>m5F@$z>rf_GfDQ=*26qQ8D!=i`gN_Od6I;^ znlBPg0Oj>xqnm)%>Q-u{Bm7t^RaERkIY=LtSJNtVN#>?*po9F=FxtvDxmCM1-gW|c99g;cc|HdKiLGuvzVDb=G zKFUK}@f61?CeC-wL)?SrAub(`XZlGUL`UPuH-E=L$N3MU!2LL%v<`GX!RM``#o7tV zs9hWN1Q4^gh0LS#0_(I>Q2V9$i|gp0ve-%DzrKRZ{_je%_|C6UEuH4U|4C*1v#(Lu zeEuhV4BtYV@Ue3XO{TN_CtGNW`YO>QvK)ZtZzU%?E6@4(%&jz6(8x@r~F$>Q+dqUfp zI={$-mKOCQM^hnZLUf=uTOr$3~zJM7(dOZ=5_|-+gBT^Q=fEPXx zZW+6zh0*qf$hdlE*~_zbGJlsO7N#WnuCeqq^%;Ss@h?@GF*|2xGD8m~6v5mGB2n>Q z>+UtC_#3)`RGCaGwYB#u6ziXs9Hc%rFf`ZJ%h*&7G5wb1iE9z(3Ev%-n;hMn^93+1 zkh>^7sXsAsOe}P{TBcIk?0C^d0`&E#Lq%O@^PzKpZEXznz z1cQl0@vJ7RK+DGM3*l5}EiFN}s|?eBp*ht`rh2A6VX6}`h+ujm$kd7x_S)X1xOw4n z#1e0cC@kOjUt_c4Kii5^F?xr8>l?Ia#Cr%j*axKG4?5{|Di?{fZFCzBex`1to2ovB z7S9Z>ubm+FG`qIl_WOMiKg+`V8RFlL%n7nC5`|4{nUb3$o&9~nfx$O zwNI1bqmHYjOO96%Cc>@sA#$TPd4s z+Yu7v@)g@@BKw&5w(T@ld_K9IR#HCC+(FYT^I3ufV;D$)e^4ibe^?0z6k2yow&GVC0%3 zpA;(A?JnVsjH-ocO$-A56@2$DdW=<>VCOwV6*pgUiW~!-8!vV}*pY^Gn#yv-APM8&9m`Q1YZ)u)N3nVI#Bo{=R}{Nh9CvCg1j?s~DBTMNW$06|ep z8d(!tz!tG(%)@l%W8EyudYRJ5H|?fT{ND^JrzZ3HhTSxY7MRaVchdw~B%W(&nc4KK z-E{Mi6^sxLdlY4bTt>WL4?W@}kJ;mw`{~Bv4MZ9|$~+N^D2o0Mk5i56V;Nn>A$1gA z`Z#GfTp3`Hly3gO<1~H9T1L($Y@ropt!U8rC-{e=JomfUaP)E=ADJ7mCXi6s%uhT) zBl$1COXG95Fm)kTs_XzSq(1|(xA3n#K`uW22^s??Q}tYA*!VpM=*B!MKz1M;41~8a zDnMu;9u;Mq=wFk$LxA7HlwAURMeZI8^1~^R_n45!9w2Q*5i77vE4d&O89r|jZ#h8j z%!dV>Jxtka!r5oR*`ESuAAjWlRg5@I13{eT!=9v3gZ2v$`}mKZpxU8_Q^p;X<8lsN zHT5CJhd)XAbcp}^lQc2&uo!=kDM#a(|3Y^=*m1^he-XQaP2Z86WZ@-NWyvC&OFsJd4J4f>yo}pW7-!n0I zhbbTQL*c!vQ4n2$!bLfv(y4qbIVtzS>@q{?;Hdb8X9#-!seCc*FBXf_97!QWTT0~~ zIj&kKIpie7PsO2nXZWAvG=_@!$RpS-y}+j)p(->6kAPwMMB9x`(R}`$BQ&C*h^W$J zM|i$W-=ZQCpx9p+?C39!z)&3FpBL4ONRmtZc zKZo5|A>Vf%7!-2PdAg(Dw+VdGaR_K?hY5W7o8%hM^!af#MdHIiM^xu!*jmMM{ zY>q=HTRcStt>RNeNG>z!UBoxPMWb`hkX)rg<8_gu77MT9PrpU=>KF(4`8&s`0Mcm9}uIIhV-IWwa;_eZ!O z3Ue&8k!)6)%<=3eH16gF4l00Tw&PeF*^5qpFc|9BYkb=;scH$C1H3Tj7G+U#1f1-h(gGIOtx^EK!LHCuqO^ z^~+QWjm|uYs-QEx`6N;jKFJck_avnc&8DR7=;nt`QZ;I>lTB+KeAQMOAHVAr`c~TD zsN{=sO6ldBegS7W{0uT~8~MsJ)IfXqV`q>M*=WA`KWC_pHuLJUGzYn_&1aE++r{^t zMb+SDIeGCGOCGkR$io&1-q}dXHaszW-Qh5@pB=@g{sPGF5|G<5kDS`^OInS%!_DlG26qRmwumcXhYdOUIH@~8hMW@Kw;t8x# zl!N9NMLA?XIF-Zl!Ko-m#Y{8R;|{A{Gmd)A#~5->f3Jl*cnu5p(*IKn_mZg(f3Jlz z5&Zvd;STn*a3>{0b3Y){g1na^o~KP^KpO6=@6k4d1H#tuX}_WL+}Bh1{<>hdQ+d~Cp-gMHxOLqDV$?4pA& z_>gMF=Yt^A9DUiruUKR2KB6hZFTw=P4*6hD5dVGZ;KM^S zD*ot4)S$AzIQY&#Qf~apB^dP^Q0rMzABN2k2u9JF_=A5$@cE@bAa+hOpLhKM`>0HQ z@elBCLwWii;rTMnH!J>#EbLJ6d}v5E?lq`ckX9wveChdw7Q@L&a6kJ5hGq=^{1X~K zdW=eyGq5K{dS#*5cC3ca3io!m2mNFCw9D9mj8Rka@`dsEWx6RHKIx4sbg;{HTbIg?y14o7HYox2-*bLe{o!PfxA2*crGXrZ;(dvedh<1 zA)ZyLs@ZKBc6UU_Q^98W51Xbc_!CjDQ>jm3ORklnD7Q&F3w+7p|M(unYVcVa7Avu^ zk^932wa)rlFLNJAgMv?rD>XBfh^P_(aA~f%Z13*Q;X9 z!O2W8B-8c&I-IoEGz5at)m^5HLQz#e8Z})u+8J|^DwWlpm92K>{B9hsamPg}jwPB} zgTXl{yh4I`d!h};dL77khVAM*oJCv0UybffIHk5HcBpk|5ohrB!F9NHR^Ba)>@Y-Wx7`xtllS@Vpyx48?;I=frd%sIe>1mHzAwK z5cNK^+6+zza!QK5T;^bV8w1U#w^6dx4GFa6p+1fWMPZ6OOh)xaEMoNs_hx%S%1||% zt}!42-gbIqjf7ZLXH;ZvG^Bq_@o4gFFlU_=HLFhCiA=PW5mtt&%?Y@oU_m0Idt>E- zW|(}gC<;`Dt8>M7O(xsLq<+y{(ilKlv(GDDDNeO(w#O$5C2*`@Rv_TO*&5>oBq5ge zRN=v9a!I?c+I`hL2|uCSpyrY+ z9x|CIt24w(q-tPBSzM5quu2pF7kB#nzIGI>LK4v-3@U)VO({D6SO- zb|EMtuI<@yl~F2+?;yVx32(x)=q?YL#1*wVY3reO<&o6T{SE66V`Qu&ix zv3YpvFZ2OF`Z;Mdn7{EkO^6Lqdg@oN4#|5R-o;3aK%8VQy<36`&%rUOM_EYa(`{B*KTjvLs?B+_qH_ z;WIn?_EfMr)V=4+>?T^fXD`d&Q_jZid7b@le5+tL@wbT0M;5n?u_9z~TN#^J(K{e; zDq;w z^DZ?N>0JVBf2?=Okw0>n_e?8sy@M_hG%{yhgDJDAZ&OEjXN!2Iv*!!r| z+2vvvv)xQ7D6!J3!myp=59YHtQZsjsV!Nm`{`x4koYDL7sxj=nG$dq3k7J)9y^=Sc z9Y8_RiSeuq0(41Sp#CU6s)&tL!G{Vr%LUEubhD+P#iMSv7s51sBD)9l{Psks*@^gx ziR?2+ekLij9g^@8&XW2e5r4IeJwtRnet$Vw8gq?D%(4)9et)m4PEjhKJ9Z^74)P=a zQ@6`9$8OICXL1gz(z$VHugSb5q#&sgx4i4i6$SmJFAMPT#>gtqTHV6|=CJu&R z^SovUEh?@gAZqFG#QYsmTpxkg5QWgNVC!*b8b$HqIy4TVQFI_&mN}(Ti%ppM3m!O> zzQiT~73Bpgw6 zFYbDo7c%4;Evp+wpjWoKtVFBOD<(^~gbzesxJu#=yOp{GdSJFVE;-FRC$q!+fl4+G zsgb8DSqqMO@!{r^s#x}ji|k_t?Ne|=QlY2ud6~uMSFy)w@R3jPLTw@qM|D$JA=jp` zY3x`gZ=1rF(=q3Laih8z_ zWv_53S^ekxd?uTTjQEUMY$c8a_swG8AwAyEz?unZ&VQHQ^`&Y+d#{oX1h0V@B>X2MohT;2#aXrr4Ti9dBFPii^*`Ho3 z(CtwC=|wmLq8r?9w2aNnKS=6aDRHubPsn+sw?{8iobmeQaHwf#F|U)) z^{}US-U_xo?bYP>B`etj40*J7SF*2z-u^cBHXY`3SFt+;6?d#+i|KUy-BrxbkU--t z9XK9B{%nDltsMNZ(EjWyvCjp`y7}TR3jnG^5OR5HE*Jhw?l70$zW;I)OrEuLZZH3Y)rg*42K5-Qn4Lz zCadu5FxpIKxs_QcTo5%WD2EZz1T2C?uM}W2+@#rWtvxPY*NEEsjx}N2I`APTG6uH6caagz1pNw!j%jtxwseLhR(nwSXWWQFxBm5LeDOq*H(vu z>v303RO9s(yb&)POY6QX81rq+$5#H~_sD+zId z;5BZa#cUZfX+97>!iv8^^yD-H@1yp3aQE806a}|!YQ#dECC)~AAQ(be;hdl-P7o@F zbcPThA*G;=h#=(7E(I;g0kJE$GkI1{$);490zZx|FTQ(fv{kdkg)4#dw1lY<-zI6r zsW2yMCQ`APVl$}OUz0exSLp-=@pSk2amNUkD*WQ|YyHVNT}@+emRWB&~zj%94p+$T1_pFn%9L+|#n|k;cR& zPe_Bf6@*h55yqLh7;r<%ubF@=gMH|46l~sGp=7%*u(XPn?R*FV!ftW3UF7p5R9x1F zHiXm2#9@6f8uNQK8JK#lDotrr5UT>k)HE5&zi^lYO9k;p$py6IQa|okxP$O*wr8Vki32W_7q4SeGkW18-XsJZzIE(@SgVzL zu=5UPRsu%p(a=0sW>Uv9-qoz0=1npDM3J4Mu(J_TR@PfTj+f{aE_-nR%e>;EIs{Z? zL1H26<|Ha8VV^8gmnn7qaxXJ_!cOO4VHw}m%oqLAF9_s?pFo8Q?tv6nAVHP*4w)CC zU*s-3Z(<>HS@?YfD>)PEgigvdj!qXP;$l8!(EF)97 zhSse*XbA4S!n4zLx0%<0so#Ll3eBni`((KWM{TGtc zk=|vjvRL+zg@7KmyF`97cg{K=vVo0u`PlARvb7065Gj(}$k}#vvlsaE@1jN_%2#e+ zg*m+#>YRyaE~@}PwI$HO;i<8KO+(Sm*$r%pqk=8tLweZ{k>vVuFKa*~obhG$AMAAp zzxZW#%2CC1e(Zm+-8hS0a38C6MAeOa=Y4F=;8Nxkb4JxIJZ&Spl(S9Eh-|20#gf)- zT|lLBM?CW@Y$n6drcG=k?TP<%6DuToIDT<6+vCWnVp)DY;5@+Z-@-=O-wyKcZDH%v z&snb~Ze+BEYIIixA|8N^y>A-$HcL%$T($2NMq$>XxuGgXM delta 18748 zcmch93w%`7x$pkg?7#$)IFW=*Ab}kSghvZzxq_rLaIGDG0#>96RzeJ(lc6nQV~6;{XFR^dPVzv(oow8+IUaTf!cr`{p6iQkMlpRqyE~W z9z*G%wxP#lI;8!o$0T}DyU=6W?2>9Vu&PC^@CG~qf14~FC)#dK-m1T;cN?#|;gBws z)&^8}uszT*N5@u{PHOXd7SS8p%{^UoR(rbVXnI$Bx97;-i~NDsW`7HC{YslcZFh7OtE?>AilCfReegM0mEg%T+rs}f*B^I-6zJX9w!w|b+@>EjcQF(S?wf= z>~pEMSykMvevn_EK=pKiZ8yNUl-g!*P-*nHw|Ep_X9-9J3E0khi+)+Qgp-r5g4 zq+{Cc1^M&}ANVw7M_wv8$LNH1{$Mu$bRN}GrP+YS4zN$FEWJhhwLKH+wA;oHppUd&6P9aoX`byo z4&R;$%d}fcb0}5YQ`(l+b>P#94v3e7&221HE`8Fo$pmuaggnaAel{UY!?ghu!&I*Q zY~r1A72(wFnYdiL^Xg)`ns5-sggIp{QZ;vZgZ5b22-!Fg$>ev5 z-quc4RM5Fd->KgwWxg#*>>cSHvFW9y(m6bpN*_gr&%DP*=lK(R$*G;*l&1apx*Yma zJNj3rJ!6f#rClY844BnSMw_;)I_aXf+Og_;FKUY1Fgwj0!21_dpU5*cwKl!aK>njO zl%|cF-$+S(PY2L^az2giUpO7Mo+h@oF$TmY#`J1$p^ZM9aQk}N(WU01sSCTg2KYNFp z-D`yS5V8#Fs-?wa$RJ23j~akfg0wQGc1fL;t=>>jQN0jp0i_{9MnTXvDE_WiQyMq8 zq>{mdm1(*hTjvdRre))pbV8?6Ky6gLYk;b*mduViwOr@1GnSTZm0tPcTLjmW;01GV{@VBpQ=6iaxjMB@oOl^}t z(5UKGR2&Uc$Qksv(?n9&u3r3rLt; z&EA#GIBQCqKN$4FK7({~2SN~w9!16f72*g5T}oAxvH~I~#wbBUIJjHDz@Bi2F-kCe zv$}*D+XDgE?Z#kbt)QV0E*`xaI2uh} zpEoE@)`||JznCg)%~hzk>7p_=ZOAxc*35!7`mT6lNE8;f`&#`TZ<7~%DE-Yih*)rg zg{8SyN_lx~jJZt>n9v&x3tJUr_mA?oxhg3BB!3_ObS=VKgVF{Q5*o#?qlpc5xlM?d z*#p%V_FO~|3sxa;(z(G}NsKC{SKtx*tZ%HfO98bN%mF&I=zP~jB_Y%T-WBa3H8^oB z2_YyL1^Csk2n!~GENrN*SUk*{s@T=lLA)=F(atma;#V^j#pIcKo#CMN^28M2Kz)Ks z!;ifUCx9RAioHNPKrIoV1PJI}AlZeW(N^yc4NII|85zTMwCi%6ASq7Nf@3}2pmyi7 z!mxBMPBEAqgXwfnP4PGB8{Om$;HX&$SbMCxK8hP^an?mcgKDE6d)0kx$Po5JjE%Eg z=a|gt(wwxVtXBK!J%dXx?M5a!Z!{#i0mu~SLZDc4YP7Z_{0dMt?TU#C94*t$!t!uz zh0|#$g7|TnI=3Xau9s7s2DNlpU0T3oNja6K`L%c46@{7I?7SkOd<3g_VFeT}G#-RS zVCUbyOwMWv%FozHC*_z%f<*an*9?Y>Z!JyaTL%@!*%6YIP4F3=5l`J;Y?P~A=l(-- zt}tLrq&$KfnXO&3VhRnpM_p)|udJ~!=1Xq0Uch42W_tX#!|>ON8~bXVo~zbM6W!UN&KmNoPKQvMqP9pm# zLB-Qju{LkxNE)kc*f>g_Korv4n=(@;POJ%dS9*O?A4wXko!sc93EI`0Zi4^!>A?zs zDt>kdozfOPJB%tK8=npIpw7q_hm&no8M*Mn14I>?f2)rwwLfkhLRGx@8X7XR%Ol8{ z9z?`RsKI)ivGxFrZ#!jp)E0M#9ubK6?ph$6qt*8;)^hHt)$i)*aOC7YYlTN5n)htq zYc<33AD|uEF-!ZCdj?f&^?WLW;l2CejGp9J;}59|BERA{Qr}K0nbzVC21Tf)P^l8p zmXKdJ>Qjc{oUidViqJw`By`_vG8QxSXF=Al`Xq=fKq>c{$)zie*5TfTB3dP=ob8rHST*XmFmQ!_S?sPG{T+0Kb_t9 z2O$E0RVk%GJKDpkZFqbr=y3F}S=!;pck6fA+M4}>HfW2Ce!}u3dnv76Up-9wRh^M- zPrfAU9h_R*Gj_A<-Ons1^8TRB4YyKCt?BeZuOp^sMefYFTGviHN)4@Nbx5H?b40-J z56LtP8V}>=;X$HOOQIMdoz+AhGu{&?4InVXx?4ddR(G9oF56r0EEVmJ`5?j^F(ZwJ z5#&}3EEIv03qnQcn7Agx)MyNJw88cZxZA>rl?k~k%qK|TfZ7&NgD}1zh+%diLg4i% z-~(@KFpr=q&`a1VMr_liEC{Lr_#47XX+hvF0OP~I#_NgAh(~{uFf(CK2E0wW&E*ZW zsVz8-E4(c@D`D|cp8z+jRA0~~6%AJAxC4lY0bo$-9HBJ$_0!v+jMCjD1Y=2%1H3861K5VjU9G|t6KJ`X6?#u)o302%w}26YTQp%||e zgFJ9$4C=fcH(1}*gt2-HFdmOlaUP(siGoGK(XqJ9PQy%q^0d(DZ6i?>F1=w*T z8d|uw)xAnk3U6B#ci4)`>T8FA4rZ{n^PjSh&w++rtG9NsYPz}kVGBbst03B2qQ4$+ zw)&dkXJJ4YOGQt&C+1n3z$Im{QW*&N!Eavzgh}Js{?H7>fDv&SB^($*kzkwJs2lqF z%vU4!uXy}w5O#9N*aIOny{(Q*Z(5ZHMgw94-Zrnw4_r%qwDVUc^G`O?72zV2TlEvu zPIUKFF|+Dfs5X`vTssqov{0#?II-HjZjOGg5RRDj&NMNfwK#nr!4BrKgqLHSNS(Va zIiSzsl5)v7zKs|VHjiMl>J_`MGsQ)N^-(6_(JAf>yWXw^X^i(^GySN;7gF3S-CiHg zWg;uZok7>>3SWot(Hg_R0q()dm0&(Z|MfMA^CZG+#!PT6P0INo*AivK7VO#g$p|4w zF3(Eg7_$pjGUvykc;p8$l-~axbdBFciv!K|8sss=pxBK#`hokx{|Nha=e|)w?p5ec zb;mS8L=i5GF>j21hM{eAGZq`hc9}w;OTM22uqvOf1Lg>Zivxw#2s!UbU@4(nyhi`w z0+A|Tu)V3t+vtTpF^`mKJI6sX_9SeaBVU0THB@~fOl5LnDTF1Ifh7^4X}dPEOCsWM z*-BrTu6Gq8(d?s#BCv9ur35>{9ROR3Ef5j|`X-lZo5S(q5i-!f)(AA{8XtTJ`4I;a zEMlOfc#Tkp3IA{+d`sdOt_|{3Se=nmGqxsG4iGw;?=}l zw|-Y^2RetacH&PxMn(N)c|H;wQU{S!h(sh9aSw}Mmey;#kHTpn{&oWmG!4LvfBQSp z+=%1YPKGzy6EEfC#qVAkMXMw9@{`H5iQkEgsCK?{kYPKTsenlF$s5dUMRE@8pvHDJ zpj*|EcYiyEjFg4~dwSxju#xY`ik$rSw=OjT_Vk1LQ{`Gfe2P2=PH-7%NhXFvxODq4br#`j*;tzknHilEe3-!BZ z>xDfozU+);qQvlMp^dhg-Hh3?qM!Gm=MxafioRo~zGxDQ<5%{gFU;HA-t>uultqs$ zJ~f3tGh6LWZ!lnA952T3SN+r{ z+T4enf*hMN>CYDXeCTA zud|}B4xnQeo?WaF2PAq@q4&G@NG5f`Mt=6wK3nuvEl{B!QB$ZhSfO;QLU!&S724~U!t^k=KZ1PYi|J`i5RX$_} zANYpfP%__8L+kM7KWk_;F5WqGR~CfKu!V@c%tHV*0Q)^71oNQdXf$muT}kvj&zncH z=%~2#=XcDb>rf!{>A`+KsJ7y$SzB?mtF}VF)oUxnU6k}^qqai7HEJuu$G<0N5myZ4 zD2><0C#>WiZJ-YmA z+7eeIY`w0W~$3E z4fFDp%kISOiMU(y>NYHJ6Nb7d>2mVf3n(p158PPq1k#4xX{=EvL$@`Wy;;g56(X+| z(6=K7A}%J-W%RnFy_a8^867Z*S!c1_^ssJ?doF9SU(9ocRUP9wTT0ud$Zqy>Ne!35 zs7}67P_Us=^Y+gUzee^;NBGJFFM*XT=1qx@)RV&s^dtXVVJxu91BsMz>9C)0&n3z+ zEn4{b)|dhajhq!my;?$^AThGEnooX?vK$vj0!6EnPQu2`j_z7cA12WoQP{2z+UQMw zRWqd3oBWYx8boLKtIf1fIYaic)$MLys6AL8Fv=ct%%UhETF*vdLGDVSclp_NYNq%3 zM{CH%*R7$TalZ?fEo*5bE~)EiG=0pctfTSrXGHhw)sXz&b>v_llSpCkBPfrg&-8dW zrw&xZeHDdHK2P*DpL`Q7=yL(YV#Fl;pd`uRkdhdG_$C?$o&Lw0XwcYXM$@PH*OnC^ zVG{B-BEc65z^qSZatfMdXopk=lOMk%{Z|r`(itCnGc9GAjNgMR41iB=rlBmGX}Kv* z?z)9COLLh>*7#rvxLa}=iF(LFKO%Ix?GkIsZ-q{GL#1~ZeWYCe<6CGRl*{Y4P%bVX z-9kB;`-w`;sO=&Z5&jU+%j3D5X+-W2MzwR)fTb*_iBNeN$|=!fNEbGI+h!U=!}*Jw zQA0P1vs-BdOJ=<0R?1At_oCu$}Uwz2i``H+E^viI#~w)(@!X~Ulq%*T!)Z~FX(MVIUcm6vl+Q|HBiOV z?xen%I~bv)v#~7J37A*$33t+7R&9X!;!Y|a`lTNKrqlWJ5m|MI+5;-hWf@|So9YC1 zrNCe=zjg~vhi3ih7U<~(;wgv!W(yT0FJbhIUc<#ZMO*)^lvc1rAU-BXAPxwUTc^v7X(V}#`wLsCfLe|F$#>xZtTyg% zyo-kRZf67|!YxVd`bwfl@1px1)FFD5UNM(QMA4ARYD6k)y)o>CU8KM(e0vv__vvOB zN}KsryJ=GII~X~t{T__ELo_J-U+@c-=%L-Py|(e>Jyest11kanrTe&h4^7P6$qc{s zA=c%$?&MGHp|RLQDxHO_^1Tnz0N(onN>1CuC}$o@gZ;jsB<&HsoP6Q~G${EY0dyym z_6eYU`BO)zf98G@@_{(W`^A`Se(V7n*r%Lz$uDfa-Rmjme|><4Cm#^N_A}{V7qF~D zCa~w@fE{8P+Ul*DeDj0UFXR1K+LN3HwD*ZO?4|7F=LNV!Ogb6|?nM(E+=H06{$d=s zKF7NucbwPnrG9jr->{cPB)=wrzR0ALQKWyax6vEi{s<1zn_`1<`I1LK_A~s3N2ry~ za_2tEO#?A=bUrJslcaaMPzh&}u>tSLq4K_fo=MWj%zjb5pE3^$3uWg)B-HE+i^Snt zSS-xY&)8*312gonF@zN?!(j-1EHrWgVC!3i3JP2K?O2_%2z{86-&I=?LNM1HGT+Q_ zi@Ap&Bn9Kc&^kyc(n9T9u@EGX@156&e7c*U$D?Cr*l zs47Iz)rE3F2nSJq2m=e*QN$#zEJ7C;RA9sGMIRVMaR6NT6?&L`mVYfgnj|uw5Zw}B zERP6vS$b(p$nQtV^;!YKFe)#R#q{E={4=4nkGF29+YfyC#(P?wZ9e>0{(V= zsVhW)98X5%$RueO0bI2rbQwne$^xt#3qeUnA;1h&lN&}}3?Y$8vzCo@G`e9IDM3;6 z-DV}D6fwIQ;B?6$edl9Y9}5Aqit{UGFT*Xb+6VXGYku!Onn)M;$$d0t#%iKMQ>*9- z1MKxRI8wGtPU!-R&$xfhxiV22vpJ9kG!w~*oPteGLrxJ~^k~tzX z6$;kqsX(a8=}$uFALA>Zq_K30?|c$O7(%o~8`zZ1Pd-U~a*Bx(2cc2{Gq60HH0s`` zXc!&l!=Iv})WhV2B1hT1Bo*6Gg3&*^=_$IOXe=M_H2G)(-}*F-F6k^W%_s{2RE2;! zd?9ie8uC<^xXq{)E+XB>_aCGIX-CMJQ{!9d$H|bTay~Eu^Qw~XjsOGwQozqgVB#e< zefm4fzNl%*scyXr52C4DAehaUAEf^OIFMcX6g}XiNVCBbtV(LKCmUiCp3o0m0c#(n{wuA-;>Y>{bTFj44+WF~UP@c2HM#>EDI@MD(u0$eb zUA@1l38AYFp8iYfo1X9%5~!V*{*tbOMb-RE8h+(^8>M(LOj-{jB&A53Y~u5h=;2?| zL7Q!}&CdV04wl^AFAz$Z`13E&V4S%OBx>9pu%xWl$wz1u4)XXT2qd238(`wFt;R-V zlo-M!H!k+SjsNKgm8K=dHSMtR_a7k_yU)hYtfTyB)lvG_q+UDqeUUn0Pn|sulP&dS z#K9io%U-5R1aBUA8BWea#+$ERrYW?Kk9&n?(m@`61<8a%eAg?K&-NL36zn${;y@fj z?APHt7LarRcMOjQ1-Slv{BbPgkOBH<$7w2NL;G!1$GyLX-;_ARQDcUoFPbwPkDK8| zeTGh_bX-h;r`Mu+uhPRd`J~OR*Uj*EUZ=i8JIOH*6)}?ZhS6V=-ZX9;(i#260ryXz zW~%(I&8WDEBIvc3!P)yqMcmO#h`5jc`6BLP<4F9YBF@0_|E-8S8ZYA5XU2Z^CDRbT z5XYxq#hs4u*S7z@`Y7JKw89mzGWD_q2%PQ0OiZjv=$@BzHD5Ln8-^H?5ycb6rV$J2 zDreBY-sno;DrN}7GzwU;uFm<`Sg{2 zUzXW59keimIMYO(wm$&#?wJ}NKGK7k+m&8S$li*22Qz)kydi$%CHSlt_#gj3@b6?j z+nD1pBu)}On6brR&W!T+F-2d2ujY>vA_=)n01U#Ml~LzM@9bgImczD4s{ zx~%Ov>WsS1&;%RHl)3k9VKB*j|JziSmn~Dyi~w@u9$5VO_%K67$!d$oESr?j?d>Bp zJ}X|tYGD<%2@VuzrYR5V|0X@be3f9WIj z=HFeQJWAnt-y%Yg%B#MGAW!4oZ%JWSNc`waFhuJ3!tanEaq~Uj(eSyd9B-Jqqna^`c)_=HhN7E?Uu7Ph8xMMVomGe95?D4=dO)l?|oUJG^WVweQ%%vT?7lK|5Yy zf5tQJ_-n*!pg?mO8$#>(G{#00ua{+IDn1TYtKDsO`8q0R@;(e`vF+8%>w;=&%1CHw&E(tSws@WV12i4fbs z9&9l0oy1y^%hB)ePhtg7jK`AL=-~$w;2-J^|BwOykQjPf{qqUS+>TYI!gtd5W_#Bn zVUCGK9!-EPI$l)QZ1#Im;Ewy_vX(3N;{$uL9=*H1SFPYhJ=rKa$(Q$Jg$PI7*^}j! zb$y)r8N0;i=%U2zGM}So+xVfLtO!T(192J4``cNOyvarz`J7}nko)YcpM0Oq{4AY6 zYzKe6#$UH%r{3jh$!rpR#jBIqw3>^*PW{?;`A^dm@wvojs_8O+FqvJ&AX82yW3|- zL-}ktosa$|pY@fqPBO_c-Gn$364(gAz0bcH#umf7S}>gLL|p2N;cOY=P;*A$yuKM- zGlKoymYqrxZ2?Q2K_D~%r|3^y>=}GX9GzSQ-UvIURC|4DKws)Sb*($#aZZtT2WC5y z1#cSv`y&a(b|Kq5E`jsZ0 z1_bqMg+xU0lsT;#(sD_q^P#NqcNi98Nf;@DaWayGirFlR2*cuq72iQD1@6B~Dkfz% zA~il0AG8HliH~W;=Vp2aPE;VH+7Khfz(VoGmPgbO3%bQV_*#ilmLQCm746;@e5FL` z*utkI`*duOh{LHKOOZIITq!voI)%@uWB=rH{A@YPtTI&%!drSs3z!*Y!f_u<;_IGS zmx$Ck90+^kAAJT%B-we#7;w{9eAgH@k0GS9dkh=K`Ei}H7U_E;%bXd zE@3~XUWaq>0-vcXRlIE+%j1r5tehPg#cRf~rF4WpHjX`-l!rmjMXw*vzN7SFn`BSm zP5z?^Y)aB_ba{n8Ie}f9KDJwrPgk;BUNDiRK^l#l$WBAeUvV{?$~u?umU-;|P-k?` ze0C!xl>^9$=yT<4J0mq(J%!!P(l^GuUIaE&A3B)`OC&0Cp#T?;7?c9ge;=lX-~2xtn?|d$N~PX;M|x>;Yck zb*#a*)3%5I^g4D5XWBE1y_!^wp$DTS)$G><>G<7jHXd?gd=2EyN&ajNE5ix?qK5eq zNp76OUb3CBJd`u}cO<29g0w>Gy8exmK>t_MA#e!u6C^z@wpeb&I zJwtJ|h?12~MhyjHXKdRgxg~apM4gJTxfh`hRGbuH@|Db1*I72R$Y&xihktSdqQQtE zBhV`bSFU7&cha1#GZ`?_bWI!4!LK8T%8sWq%!;EZFXoI<}C`Mk|-I76yZ!M;h1#Vaq@5X3MY0mGcCgW~BnN zu2Hr0-}m98SFjJ0Hi2euL?gqAqzkdUpVBZSpUy&s95kCeQXbIo8p52@bMQ)dq zzC1mb=WbwwVJTN^V0~&;<|v)ktTwKyMbbi-vR>vW(p#=E4^FdJ{HVs-rIVfHNWt=q^dWmR_Uq2Ia1G2>1w!*G!-oh64JZ+5PFK%HW^Wi{r%2w7N6-Lozcd^gOc2vGEI`?k2 T+y=?>l*YzU(&^gcvh;reJ)K$e From 1782fc6f26196dcf3f3f7b20ebd4b3c514e36777 Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Mon, 16 Feb 2026 10:08:02 +0800 Subject: [PATCH 20/26] fix: Womhole integration update --- tests/wormhole_integration.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/wormhole_integration.rs b/tests/wormhole_integration.rs index b0e33a9..154e39e 100644 --- a/tests/wormhole_integration.rs +++ b/tests/wormhole_integration.rs @@ -248,8 +248,9 @@ async fn submit_wormhole_transfer( println!(" Unspendable account: 0x{}", hex::encode(unspendable_account_bytes)); println!(" Exit account: 0x{}", hex::encode(exit_account_bytes)); - // Create and submit transfer to unspendable account - let transfer_tx = quantus_node::api::tx().wormhole().transfer_native( + // Fund via Balances (wormhole has no transfer_native; WormholeProofRecorderExtension + // records every Balances transfer and emits NativeTransferred) + let transfer_tx = quantus_node::api::tx().balances().transfer_allow_death( subxt::ext::subxt_core::utils::MultiAddress::Id(unspendable_account_id.clone()), funding_amount, ); @@ -262,13 +263,17 @@ async fn submit_wormhole_transfer( }; // Submit transaction and get the actual block hash where it was included - let block_hash = submit_and_get_block_hash(quantus_client, &quantum_keypair, transfer_tx) - .await - .map_err(|e| format!("Transfer failed: {}", e))?; + let block_hash: subxt::utils::H256 = submit_and_get_block_hash( + quantus_client, + &quantum_keypair, + transfer_tx, + ) + .await + .map_err(|e| format!("Transfer failed: {}", e))?; println!(" Transfer included in block: {:?}", block_hash); - // Find the NativeTransferred event that matches our unspendable account + // WormholeProofRecorderExtension emits NativeTransferred for every Balances transfer let events_api = client .events() .at(block_hash) @@ -457,7 +462,7 @@ async fn submit_single_proof_for_verification( ) -> Result<(), String> { println!(" Submitting single proof for on-chain verification..."); - let verify_tx = quantus_node::api::tx().wormhole().verify_wormhole_proof(proof_bytes); + let verify_tx = quantus_node::api::tx().wormhole().verify_aggregated_proof(proof_bytes); let unsigned_tx = quantus_client .client() From ed1bce4642a15bbfc913c742038bab0a2b5a5b42 Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Mon, 16 Feb 2026 10:09:10 +0800 Subject: [PATCH 21/26] fix: FMT --- tests/wormhole_integration.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/wormhole_integration.rs b/tests/wormhole_integration.rs index 154e39e..2afdf66 100644 --- a/tests/wormhole_integration.rs +++ b/tests/wormhole_integration.rs @@ -263,13 +263,10 @@ async fn submit_wormhole_transfer( }; // Submit transaction and get the actual block hash where it was included - let block_hash: subxt::utils::H256 = submit_and_get_block_hash( - quantus_client, - &quantum_keypair, - transfer_tx, - ) - .await - .map_err(|e| format!("Transfer failed: {}", e))?; + let block_hash: subxt::utils::H256 = + submit_and_get_block_hash(quantus_client, &quantum_keypair, transfer_tx) + .await + .map_err(|e| format!("Transfer failed: {}", e))?; println!(" Transfer included in block: {:?}", block_hash); From b89a4d28fc5f64a021ea70278612fd83ea663a0a Mon Sep 17 00:00:00 2001 From: illuzen Date: Mon, 16 Feb 2026 11:22:51 +0800 Subject: [PATCH 22/26] parent_hash is private input now --- src/cli/wormhole.rs | 13 +++++-------- tests/wormhole_integration.rs | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index b60957a..36e1c04 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -1913,6 +1913,7 @@ async fn generate_proof( .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, storage_proof: processed_storage_proof, unspendable_account: unspendable_account_bytes_digest, + parent_hash, state_root, extrinsics_root, digest, @@ -1929,7 +1930,6 @@ async fn generate_proof( .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, block_hash: BytesDigest::try_from(block_hash.as_ref()) .map_err(|e| crate::error::QuantusError::Generic(e.to_string()))?, - parent_hash, block_number, asset_id: NATIVE_ASSET_ID, }, @@ -2310,7 +2310,6 @@ async fn parse_proof_file( log_print!("Exit Account 1: 0x{}", hex::encode(pi.exit_account_1.as_ref())); log_print!("Exit Account 2: 0x{}", hex::encode(pi.exit_account_2.as_ref())); log_print!("Block Hash: 0x{}", hex::encode(pi.block_hash.as_ref())); - log_print!("Parent Hash: 0x{}", hex::encode(pi.parent_hash.as_ref())); log_print!("Block Number: {}", pi.block_number); // Verify if requested @@ -2530,12 +2529,12 @@ mod tests { ASSET_ID_INDEX, BLOCK_HASH_END_INDEX, BLOCK_HASH_START_INDEX, BLOCK_NUMBER_INDEX, EXIT_ACCOUNT_1_END_INDEX, EXIT_ACCOUNT_1_START_INDEX, EXIT_ACCOUNT_2_END_INDEX, EXIT_ACCOUNT_2_START_INDEX, NULLIFIER_END_INDEX, NULLIFIER_START_INDEX, - OUTPUT_AMOUNT_1_INDEX, OUTPUT_AMOUNT_2_INDEX, PARENT_HASH_END_INDEX, - PARENT_HASH_START_INDEX, PUBLIC_INPUTS_FELTS_LEN, VOLUME_FEE_BPS_INDEX, + OUTPUT_AMOUNT_1_INDEX, OUTPUT_AMOUNT_2_INDEX, PUBLIC_INPUTS_FELTS_LEN, + VOLUME_FEE_BPS_INDEX, }; // Verify expected public inputs layout for dual-output circuit - assert_eq!(PUBLIC_INPUTS_FELTS_LEN, 25, "Public inputs should be 25 field elements"); + assert_eq!(PUBLIC_INPUTS_FELTS_LEN, 21, "Public inputs should be 21 field elements"); assert_eq!(ASSET_ID_INDEX, 0, "Asset ID should be first"); assert_eq!(OUTPUT_AMOUNT_1_INDEX, 1, "Output amount 1 should be at index 1"); assert_eq!(OUTPUT_AMOUNT_2_INDEX, 2, "Output amount 2 should be at index 2"); @@ -2548,9 +2547,7 @@ mod tests { assert_eq!(EXIT_ACCOUNT_2_END_INDEX, 16, "Exit account 2 should end at index 16"); assert_eq!(BLOCK_HASH_START_INDEX, 16, "Block hash should start at index 16"); assert_eq!(BLOCK_HASH_END_INDEX, 20, "Block hash should end at index 20"); - assert_eq!(PARENT_HASH_START_INDEX, 20, "Parent hash should start at index 20"); - assert_eq!(PARENT_HASH_END_INDEX, 24, "Parent hash should end at index 24"); - assert_eq!(BLOCK_NUMBER_INDEX, 24, "Block number should be at index 24"); + assert_eq!(BLOCK_NUMBER_INDEX, 20, "Block number should be at index 20"); } /// Test that constants match expected on-chain configuration diff --git a/tests/wormhole_integration.rs b/tests/wormhole_integration.rs index b0e33a9..4742523 100644 --- a/tests/wormhole_integration.rs +++ b/tests/wormhole_integration.rs @@ -410,6 +410,7 @@ async fn generate_proof_from_transfer( .map_err(|e| format!("Failed to convert funding account: {}", e))?, storage_proof: processed_storage_proof, unspendable_account: digest_felts_to_bytes(transfer_data.unspendable_account), + parent_hash, state_root, extrinsics_root, digest, @@ -427,7 +428,6 @@ async fn generate_proof_from_transfer( .map_err(|e| format!("Failed to convert zero exit account: {}", e))?, block_hash: BytesDigest::try_from(block_hash.as_ref()) .map_err(|e| format!("Failed to convert block hash: {}", e))?, - parent_hash, block_number, asset_id: NATIVE_ASSET_ID, }, @@ -538,7 +538,7 @@ fn aggregate_proofs( println!(" exit_account_1: {:?}", ctx.public_inputs.exit_account_1); println!(" exit_account_2: {:?}", ctx.public_inputs.exit_account_2); println!(" block_hash: {:?}", ctx.public_inputs.block_hash); - println!(" parent_hash: {:?}", ctx.public_inputs.parent_hash); + println!(" block_number: {:?}", ctx.public_inputs.block_number); println!(" block_number: {}", ctx.public_inputs.block_number); aggregator .push_proof(ctx.proof) From 49f602b21094ce5a7478928a2e467f58ef8cfa32 Mon Sep 17 00:00:00 2001 From: Ethan Date: Sun, 15 Feb 2026 21:26:41 -0600 Subject: [PATCH 23/26] address DRY violations and 5,6 8. --- src/cli/wormhole.rs | 668 +++++++++++++++++++++++++++++--------------- 1 file changed, 437 insertions(+), 231 deletions(-) diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index b60957a..36acbc1 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -111,38 +111,17 @@ impl AggregationConfig { }) }; - if let Some(ref expected) = stored_hashes.aggregated_common { - if let Some(actual) = hash_file("aggregated_common.bin") { - if expected != &actual { - mismatches.push(format!( - "aggregated_common.bin: expected {}..., got {}...", - &expected[..16.min(expected.len())], - &actual[..16.min(actual.len())] - )); - } - } - } - - if let Some(ref expected) = stored_hashes.aggregated_verifier { - if let Some(actual) = hash_file("aggregated_verifier.bin") { - if expected != &actual { - mismatches.push(format!( - "aggregated_verifier.bin: expected {}..., got {}...", - &expected[..16.min(expected.len())], - &actual[..16.min(actual.len())] - )); - } - } - } - - if let Some(ref expected) = stored_hashes.prover { - if let Some(actual) = hash_file("prover.bin") { - if expected != &actual { - mismatches.push(format!( - "prover.bin: expected {}..., got {}...", - &expected[..16.min(expected.len())], - &actual[..16.min(actual.len())] - )); + let checks = [ + ("aggregated_common.bin", &stored_hashes.aggregated_common), + ("aggregated_verifier.bin", &stored_hashes.aggregated_verifier), + ("prover.bin", &stored_hashes.prover), + ]; + for (filename, expected_hash) in checks { + if let Some(ref expected) = expected_hash { + if let Some(actual) = hash_file(filename) { + if expected != &actual { + mismatches.push(format!("{}...", filename)); + } } } } @@ -281,7 +260,7 @@ pub fn random_partition(total: u128, n: usize, min_per_part: u128) -> Vec if diff != 0 { // Add/subtract difference from a random part let idx = rng.random_range(0..n); - parts[idx] = (parts[idx] as i128 + diff) as u128; + parts[idx] = (parts[idx] as i128 + diff).max(0) as u128; } parts @@ -930,34 +909,42 @@ async fn aggregate_proofs( Ok(()) } -async fn verify_aggregated_proof(proof_file: String, node_url: &str) -> crate::error::Result<()> { - use subxt::tx::TxStatus; +#[derive(Debug, Clone, Copy)] +enum IncludedAt { + Best, + Finalized, +} - log_print!("Verifying aggregated wormhole proof on-chain..."); +impl IncludedAt { + fn label(self) -> &'static str { + match self { + IncludedAt::Best => "best block", + IncludedAt::Finalized => "finalized block", + } + } +} - // Read proof from file - let proof_hex = std::fs::read_to_string(&proof_file).map_err(|e| { +fn read_hex_proof_file_to_bytes(proof_file: &str) -> crate::error::Result> { + let proof_hex = std::fs::read_to_string(proof_file).map_err(|e| { crate::error::QuantusError::Generic(format!("Failed to read proof file: {}", e)) })?; let proof_bytes = hex::decode(proof_hex.trim()) .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to decode hex: {}", e)))?; - log_verbose!("Aggregated proof size: {} bytes", proof_bytes.len()); - - // Connect to node - let quantus_client = QuantusClient::new(node_url) - .await - .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to connect: {}", e)))?; + Ok(proof_bytes) +} - log_verbose!("Connected to node"); +/// Submit unsigned verify_aggregated_proof(proof_bytes) and return (included_at, block_hash, +/// tx_hash). +async fn submit_unsigned_verify_aggregated_proof( + quantus_client: &QuantusClient, + proof_bytes: Vec, +) -> crate::error::Result<(IncludedAt, subxt::utils::H256, subxt::utils::H256)> { + use subxt::tx::TxStatus; - // Create the verify_aggregated_proof transaction payload let verify_tx = quantus_node::api::tx().wormhole().verify_aggregated_proof(proof_bytes); - log_verbose!("Submitting unsigned aggregated verification transaction..."); - - // Submit as unsigned extrinsic let unsigned_tx = quantus_client.client().tx().create_unsigned(&verify_tx).map_err(|e| { crate::error::QuantusError::Generic(format!("Failed to create unsigned tx: {}", e)) })?; @@ -967,67 +954,21 @@ async fn verify_aggregated_proof(proof_file: String, node_url: &str) -> crate::e .await .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to submit tx: {}", e)))?; - // Wait for transaction inclusion and verify events while let Some(Ok(status)) = tx_progress.next().await { - log_verbose!("Transaction status: {:?}", status); match status { TxStatus::InBestBlock(tx_in_block) => { - let block_hash = tx_in_block.block_hash(); - let tx_hash = tx_in_block.extrinsic_hash(); - - // Check for ProofVerified event - let result = check_proof_verification_events( - quantus_client.client(), - &block_hash, - &tx_hash, - crate::log::is_verbose(), - ) - .await?; - - if result.success { - log_success!("Aggregated proof verified successfully on-chain!"); - if let Some(amount) = result.exit_amount { - log_success!("Total exit amount: {}", format_balance(amount)); - } - log_verbose!("Included in block: {:?}", block_hash); - return Ok(()); - } else { - let error_msg = result.error_message.unwrap_or_else(|| { - "Aggregated proof verification failed - no ProofVerified event found" - .to_string() - }); - log_error!("❌ {}", error_msg); - return Err(crate::error::QuantusError::Generic(error_msg)); - } + return Ok(( + IncludedAt::Best, + tx_in_block.block_hash(), + tx_in_block.extrinsic_hash(), + )); }, TxStatus::InFinalizedBlock(tx_in_block) => { - let block_hash = tx_in_block.block_hash(); - let tx_hash = tx_in_block.extrinsic_hash(); - - // Check for ProofVerified event - let result = check_proof_verification_events( - quantus_client.client(), - &block_hash, - &tx_hash, - crate::log::is_verbose(), - ) - .await?; - - if result.success { - log_success!("Aggregated proof verified successfully on-chain!"); - if let Some(amount) = result.exit_amount { - log_success!("Total exit amount: {}", format_balance(amount)); - } - log_verbose!("Finalized in block: {:?}", block_hash); - return Ok(()); - } else { - let error_msg = result.error_message.unwrap_or_else(|| { - "Aggregated proof verification failed - no ProofVerified event found" - .to_string() - }); - log_error!("❌ {}", error_msg); - return Err(crate::error::QuantusError::Generic(error_msg)); - } + return Ok(( + IncludedAt::Finalized, + tx_in_block.block_hash(), + tx_in_block.extrinsic_hash(), + )); }, TxStatus::Error { message } | TxStatus::Invalid { message } => { return Err(crate::error::QuantusError::Generic(format!( @@ -1042,6 +983,121 @@ async fn verify_aggregated_proof(proof_file: String, node_url: &str) -> crate::e Err(crate::error::QuantusError::Generic("Transaction stream ended unexpectedly".to_string())) } +/// Collect wormhole events for our extrinsic (by tx_hash) in a given block. +/// Returns (found_proof_verified, native_transfers). +async fn collect_wormhole_events_for_extrinsic( + quantus_client: &QuantusClient, + block_hash: subxt::utils::H256, + tx_hash: subxt::utils::H256, +) -> crate::error::Result<(bool, Vec)> { + use crate::chain::quantus_subxt::api::system::events::ExtrinsicFailed; + + let block = + quantus_client.client().blocks().at(block_hash).await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) + })?; + + let events = block + .events() + .await + .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to get events: {}", e)))?; + + let extrinsics = block.extrinsics().await.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to get extrinsics: {}", e)) + })?; + + let our_ext_idx = extrinsics + .iter() + .enumerate() + .find(|(_, ext)| ext.hash() == tx_hash) + .map(|(idx, _)| idx as u32) + .ok_or_else(|| { + crate::error::QuantusError::Generic( + "Could not find submitted extrinsic in included block".to_string(), + ) + })?; + + let mut transfer_events = Vec::new(); + let mut found_proof_verified = false; + + log_verbose!(" Events for our extrinsic (idx={}):", our_ext_idx); + + for event_result in events.iter() { + let event = event_result.map_err(|e| { + crate::error::QuantusError::Generic(format!("Failed to decode event: {}", e)) + })?; + + if let subxt::events::Phase::ApplyExtrinsic(ext_idx) = event.phase() { + if ext_idx == our_ext_idx { + log_print!(" Event: {}::{}", event.pallet_name(), event.variant_name()); + + // Decode ExtrinsicFailed to get the specific error + if let Ok(Some(ExtrinsicFailed { dispatch_error, .. })) = + event.as_event::() + { + let metadata = quantus_client.client().metadata(); + let error_msg = format_dispatch_error(&dispatch_error, &metadata); + log_print!(" DispatchError: {}", error_msg); + } + + if let Ok(Some(_)) = event.as_event::() { + found_proof_verified = true; + } + + if let Ok(Some(transfer)) = event.as_event::() + { + transfer_events.push(transfer); + } + } + } + } + + Ok((found_proof_verified, transfer_events)) +} + +async fn verify_aggregated_proof(proof_file: String, node_url: &str) -> crate::error::Result<()> { + log_print!("Verifying aggregated wormhole proof on-chain..."); + + let proof_bytes = read_hex_proof_file_to_bytes(&proof_file)?; + log_verbose!("Aggregated proof size: {} bytes", proof_bytes.len()); + + // Connect to node + let quantus_client = QuantusClient::new(node_url) + .await + .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to connect: {}", e)))?; + log_verbose!("Connected to node"); + + log_verbose!("Submitting unsigned aggregated verification transaction..."); + + let (included_at, block_hash, tx_hash) = + submit_unsigned_verify_aggregated_proof(&quantus_client, proof_bytes).await?; + + // One unified check (no best/finalized copy-paste) + let result = check_proof_verification_events( + quantus_client.client(), + &block_hash, + &tx_hash, + crate::log::is_verbose(), + ) + .await?; + + if result.success { + log_success!("Aggregated proof verified successfully on-chain!"); + if let Some(amount) = result.exit_amount { + log_success!("Total exit amount: {}", format_balance(amount)); + } + + log_verbose!("Included in {}: {:?}", included_at.label(), block_hash); + return Ok(()); + } + + let error_msg = result.error_message.unwrap_or_else(|| { + "Aggregated proof verification failed - no ProofVerified event found".to_string() + }); + log_error!("❌ {}", error_msg); + Err(crate::error::QuantusError::Generic(error_msg)) +} + // ============================================================================ // Multi-round wormhole flow implementation // ============================================================================ @@ -1098,10 +1154,12 @@ async fn get_minting_account( Ok(minting_account) } -/// Parse transfer info from NativeTransferred events in a block +/// Parse transfer info from NativeTransferred events in a block and updates block hash for all +/// transfers fn parse_transfer_events( events: &[wormhole::events::NativeTransferred], expected_addresses: &[SubxtAccountId], + block_hash: subxt::utils::H256, ) -> Result, crate::error::QuantusError> { let mut transfer_infos = Vec::new(); @@ -1115,7 +1173,7 @@ fn parse_transfer_events( })?; transfer_infos.push(TransferInfo { - block_hash: subxt::utils::H256::default(), // Will be set by caller + block_hash, transfer_count: matching_event.transfer_count, amount: matching_event.amount, wormhole_address: expected_addr.clone(), @@ -1725,12 +1783,8 @@ async fn run_multiround( }) .collect(); - current_transfers = parse_transfer_events(&transfer_events, &next_round_addresses)?; - - // Update block hash for all transfers - for transfer in &mut current_transfers { - transfer.block_hash = verification_block; - } + current_transfers = + parse_transfer_events(&transfer_events, &next_round_addresses, verification_block)?; log_print!( " Captured {} transfer(s) for round {}", @@ -1962,17 +2016,9 @@ async fn verify_aggregated_and_get_events( proof_file: &str, quantus_client: &QuantusClient, ) -> crate::error::Result<(subxt::utils::H256, Vec)> { - use crate::chain::quantus_subxt::api::system::events::ExtrinsicFailed; use qp_wormhole_verifier::WormholeVerifier; - use subxt::tx::TxStatus; - // Read proof from file - let proof_hex = std::fs::read_to_string(proof_file).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to read proof file: {}", e)) - })?; - - let proof_bytes = hex::decode(proof_hex.trim()) - .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to decode hex: {}", e)))?; + let proof_bytes = read_hex_proof_file_to_bytes(proof_file)?; // Verify locally before submitting on-chain log_verbose!("Verifying aggregated proof locally before on-chain submission..."); @@ -1985,7 +2031,6 @@ async fn verify_aggregated_and_get_events( crate::error::QuantusError::Generic(format!("Failed to load aggregated verifier: {}", e)) })?; - // Use the verifier crate's ProofWithPublicInputs type (different from plonky2's) let proof = qp_wormhole_verifier::ProofWithPublicInputs::< qp_wormhole_verifier::F, qp_wormhole_verifier::C, @@ -2006,120 +2051,41 @@ async fn verify_aggregated_and_get_events( })?; log_verbose!("Local verification passed!"); - // Create the verify_aggregated_proof transaction payload - let verify_tx = quantus_node::api::tx().wormhole().verify_aggregated_proof(proof_bytes); + // Submit unsigned tx + wait for inclusion (best or finalized) + let (included_at, block_hash, tx_hash) = + submit_unsigned_verify_aggregated_proof(quantus_client, proof_bytes).await?; - // Submit as unsigned extrinsic - let unsigned_tx = quantus_client.client().tx().create_unsigned(&verify_tx).map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to create unsigned tx: {}", e)) - })?; + log_verbose!( + "Submitted tx included in {}: block={:?}, tx={:?}", + included_at.label(), + block_hash, + tx_hash + ); - let mut tx_progress = unsigned_tx - .submit_and_watch() - .await - .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to submit tx: {}", e)))?; + // Collect events for our extrinsic only + let (found_proof_verified, transfer_events) = + collect_wormhole_events_for_extrinsic(quantus_client, block_hash, tx_hash).await?; - while let Some(Ok(status)) = tx_progress.next().await { - match status { - TxStatus::InBestBlock(tx_in_block) => { - let block_hash = tx_in_block.block_hash(); - let tx_hash = tx_in_block.extrinsic_hash(); - - // Get all events from the block - let block = quantus_client.client().blocks().at(block_hash).await.map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) - })?; - - let events = block.events().await.map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to get events: {}", e)) - })?; - - // Find our extrinsic index - let extrinsics = block.extrinsics().await.map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to get extrinsics: {}", e)) - })?; - - let our_ext_idx = extrinsics - .iter() - .enumerate() - .find(|(_, ext)| ext.hash() == tx_hash) - .map(|(idx, _)| idx as u32); - - // Collect NativeTransferred events for our extrinsic - let mut transfer_events = Vec::new(); - let mut found_proof_verified = false; - - log_verbose!(" Events for our extrinsic (idx={:?}):", our_ext_idx); - for event_result in events.iter() { - let event = event_result.map_err(|e| { - crate::error::QuantusError::Generic(format!( - "Failed to decode event: {}", - e - )) - })?; - - if let subxt::events::Phase::ApplyExtrinsic(ext_idx) = event.phase() { - if Some(ext_idx) == our_ext_idx { - // Log all events for our extrinsic - log_print!( - " Event: {}::{}", - event.pallet_name(), - event.variant_name() - ); - - // Decode ExtrinsicFailed to get the specific error - if let Ok(Some(ExtrinsicFailed { dispatch_error, .. })) = - event.as_event::() - { - let metadata = quantus_client.client().metadata(); - let error_msg = format_dispatch_error(&dispatch_error, &metadata); - log_print!(" DispatchError: {}", error_msg); - } - - if let Ok(Some(_)) = event.as_event::() - { - found_proof_verified = true; - } - if let Ok(Some(transfer)) = - event.as_event::() - { - transfer_events.push(transfer); - } - } - } - } + if !found_proof_verified { + return Err(crate::error::QuantusError::Generic( + "Proof verification failed - no ProofVerified event".to_string(), + )); + } - if found_proof_verified { - // Log the minted amounts from transfer events - log_print!(" Tokens minted (from NativeTransferred events):"); - for (idx, transfer) in transfer_events.iter().enumerate() { - let to_hex = hex::encode(transfer.to.0); - log_print!( - " [{}] {} -> {} planck ({})", - idx, - to_hex, - transfer.amount, - format_balance(transfer.amount) - ); - } - return Ok((block_hash, transfer_events)); - } else { - return Err(crate::error::QuantusError::Generic( - "Proof verification failed - no ProofVerified event".to_string(), - )); - } - }, - TxStatus::Error { message } | TxStatus::Invalid { message } => { - return Err(crate::error::QuantusError::Generic(format!( - "Transaction failed: {}", - message - ))); - }, - _ => continue, - } + // Log minted amounts + log_print!(" Tokens minted (from NativeTransferred events):"); + for (idx, transfer) in transfer_events.iter().enumerate() { + let to_hex = hex::encode(transfer.to.0); + log_print!( + " [{}] {} -> {} planck ({})", + idx, + to_hex, + transfer.amount, + format_balance(transfer.amount) + ); } - Err(crate::error::QuantusError::Generic("Transaction stream ended unexpectedly".to_string())) + Ok((block_hash, transfer_events)) } /// Dry run - show what would happen without executing @@ -2337,6 +2303,7 @@ async fn parse_proof_file( #[cfg(test)] mod tests { use super::*; + use std::collections::HashSet; use tempfile::NamedTempFile; #[test] @@ -2577,4 +2544,243 @@ mod tests { // Ensure VOLUME_FEE_BPS matches expected value (10 bps = 0.1%) assert_eq!(VOLUME_FEE_BPS, 10); } + fn mk_accounts(n: usize) -> Vec<[u8; 32]> { + (0..n) + .map(|i| { + let mut a = [0u8; 32]; + a[0] = (i as u8).wrapping_add(1); // avoid [0;32] + a + }) + .collect() + } + + fn proof_outputs_for_inputs(input_amounts: &[u128], fee_bps: u32) -> Vec { + input_amounts + .iter() + .map(|&input| { + let input_quantized = quantize_funding_amount(input).unwrap_or(0); + compute_output_amount(input_quantized, fee_bps) + }) + .collect() + } + + fn total_output_for_inputs(input_amounts: &[u128], fee_bps: u32) -> u64 { + proof_outputs_for_inputs(input_amounts, fee_bps) + .into_iter() + .map(|x| x as u64) + .sum() + } + + /// Find some input that yields at least `min_out` quantized output after fee. + /// Keeps tests robust even if quantization constants change. + fn find_input_for_min_output(fee_bps: u32, min_out: u32) -> u128 { + let mut input: u128 = 1; + for _ in 0..80 { + let q = quantize_funding_amount(input).unwrap_or(0); + let out = compute_output_amount(q, fee_bps); + if out >= min_out { + return input; + } + // grow fast but safely + input = input.saturating_mul(10); + } + panic!("Could not find input producing output >= {}", min_out); + } + + // -------------------------- + // random_partition tests + // -------------------------- + + #[test] + fn random_partition_n0() { + let parts = random_partition(100, 0, 1); + assert!(parts.is_empty()); + } + + #[test] + fn random_partition_n1() { + let total = 12345u128; + let parts = random_partition(total, 1, 9999); + assert_eq!(parts, vec![total]); + } + + #[test] + fn random_partition_total_less_than_min_total_falls_back_to_equalish() { + // total < min_per_part * n => fallback path + let total = 5u128; + let n = 10usize; + let min_per_part = 1u128; + + let parts = random_partition(total, n, min_per_part); + + assert_eq!(parts.len(), n); + assert_eq!(parts.iter().sum::(), total); + + // fallback behavior: per_part=0, remainder=5, last gets remainder + for part in parts.iter().take(n - 1) { + assert_eq!(*part, 0); + } + assert_eq!(parts[n - 1], 5); + } + + #[test] + fn random_partition_min_achievable_invariants_hold() { + let total = 100u128; + let n = 10usize; + let min_per_part = 3u128; + + for _ in 0..200 { + let parts = random_partition(total, n, min_per_part); + assert_eq!(parts.len(), n); + assert_eq!(parts.iter().sum::(), total); + assert!(parts.iter().all(|&p| p >= min_per_part)); + } + } + + #[test] + fn random_partition_distributable_zero_all_min() { + let n = 10usize; + let min_per_part = 3u128; + let total = min_per_part * n as u128; + + let parts = random_partition(total, n, min_per_part); + + assert_eq!(parts.len(), n); + assert_eq!(parts.iter().sum::(), total); + assert!(parts.iter().all(|&p| p == min_per_part)); + } + + // -------------------------- + // compute_random_output_assignments tests + // -------------------------- + + #[test] + fn compute_random_output_assignments_empty_inputs_or_targets() { + let targets = mk_accounts(3); + assert!(compute_random_output_assignments(&[], &targets, 0).is_empty()); + + let inputs = vec![1u128, 2u128, 3u128]; + assert!(compute_random_output_assignments(&inputs, &[], 0).is_empty()); + } + + #[test] + fn compute_random_output_assignments_basic_invariants() { + let fee_bps = 0u32; + + // ensure non-zero outputs for meaningful checks + let input = find_input_for_min_output(fee_bps, 5); + let input_amounts = vec![input, input, input, input, input]; + let targets = mk_accounts(4); + + let assignments = compute_random_output_assignments(&input_amounts, &targets, fee_bps); + assert_eq!(assignments.len(), input_amounts.len()); + + let proof_outputs = proof_outputs_for_inputs(&input_amounts, fee_bps); + + // per-proof sum matches + for (i, a) in assignments.iter().enumerate() { + let per_proof_sum = a.output_amount_1 as u64 + a.output_amount_2 as u64; + assert_eq!(per_proof_sum, proof_outputs[i] as u64); + + // If an output amount is non-zero, the account must be in targets + if a.output_amount_1 > 0 { + assert!(targets.contains(&a.exit_account_1)); + } else { + // if amount is zero, account can be zero or anything; current impl keeps default + // [0;32] + } + if a.output_amount_2 > 0 { + assert!(targets.contains(&a.exit_account_2)); + assert_ne!(a.exit_account_2, a.exit_account_1); // should be different if both used + } else { + // current impl keeps default [0;32] + assert_eq!(a.exit_account_2, [0u8; 32]); + } + } + + // total sum matches + let total_assigned: u64 = assignments + .iter() + .map(|a| a.output_amount_1 as u64 + a.output_amount_2 as u64) + .sum(); + + let total_expected = total_output_for_inputs(&input_amounts, fee_bps); + assert_eq!(total_assigned, total_expected); + } + + #[test] + fn compute_random_output_assignments_more_targets_than_capacity_still_conserves_funds() { + // Capacity: each proof can hit at most 2 targets, so distinct-used-targets <= 2 * + // num_proofs. Set num_targets > 2*num_proofs and ensure total_output >= num_targets so + // the partition *wants* to give each target >= 1 (though algorithm can't satisfy it). + let fee_bps = 0u32; + let num_proofs = 1usize; + let num_targets = 5usize; + + let input = find_input_for_min_output(fee_bps, 10); // ensure total_output is "big enough" + let input_amounts = vec![input; num_proofs]; + let targets = mk_accounts(num_targets); + + let assignments = compute_random_output_assignments(&input_amounts, &targets, fee_bps); + assert_eq!(assignments.len(), num_proofs); + + // total preserved + let total_assigned: u64 = assignments + .iter() + .map(|a| a.output_amount_1 as u64 + a.output_amount_2 as u64) + .sum(); + let total_expected = total_output_for_inputs(&input_amounts, fee_bps); + assert_eq!(total_assigned, total_expected); + + // used targets bounded by 2*num_proofs and thus < num_targets + let mut used = HashSet::new(); + for a in &assignments { + if a.output_amount_1 > 0 { + used.insert(a.exit_account_1); + } + if a.output_amount_2 > 0 { + used.insert(a.exit_account_2); + } + } + assert!(used.len() <= 2 * num_proofs); + assert!(used.len() < num_targets); + } + + #[test] + fn compute_random_output_assignments_total_output_less_than_num_targets_does_not_panic_and_conserves( + ) { + // This forces random_partition into its fallback branch inside + // compute_random_output_assignments because min_per_target = 1 and total_output < + // num_targets. + let fee_bps = 0u32; + + let num_targets = 50usize; + let targets = mk_accounts(num_targets); + + // Try to get very small total output: two proofs with output likely >= 1 each, + // but still far less than 50. + let input = find_input_for_min_output(fee_bps, 1); + let input_amounts = vec![input, input]; + + let assignments = compute_random_output_assignments(&input_amounts, &targets, fee_bps); + assert_eq!(assignments.len(), input_amounts.len()); + + let total_assigned: u64 = assignments + .iter() + .map(|a| a.output_amount_1 as u64 + a.output_amount_2 as u64) + .sum(); + let total_expected = total_output_for_inputs(&input_amounts, fee_bps); + assert_eq!(total_assigned, total_expected); + + // For each assignment: if non-zero amount then account must be in targets. + for a in &assignments { + if a.output_amount_1 > 0 { + assert!(targets.contains(&a.exit_account_1)); + } + if a.output_amount_2 > 0 { + assert!(targets.contains(&a.exit_account_2)); + assert_ne!(a.exit_account_2, a.exit_account_1); + } + } + } } From 63d4e552a8bda276c5b6248d3ec37825d91cbecf Mon Sep 17 00:00:00 2001 From: illuzen Date: Mon, 16 Feb 2026 12:01:50 +0800 Subject: [PATCH 24/26] update bins and versions --- .gitignore | 1 + Cargo.lock | 40 ++++++++++++------------- Cargo.toml | 12 ++++---- generated-bins/aggregated_common.bin | Bin 0 -> 1353 bytes generated-bins/aggregated_verifier.bin | Bin 0 -> 552 bytes generated-bins/common.bin | Bin 0 -> 1057 bytes generated-bins/config.json | 12 ++++++++ generated-bins/verifier.bin | Bin 0 -> 552 bytes src/cli/wormhole.rs | 30 +++++++++++++++++++ 9 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 generated-bins/aggregated_common.bin create mode 100644 generated-bins/aggregated_verifier.bin create mode 100644 generated-bins/common.bin create mode 100644 generated-bins/config.json create mode 100644 generated-bins/verifier.bin diff --git a/.gitignore b/.gitignore index 1b9cbf1..628b5e4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target .idea *.hex +/generated-bins/prover.bin diff --git a/Cargo.lock b/Cargo.lock index a041702..c723444 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,7 +1008,7 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1420,7 +1420,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -1611,7 +1611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3122,7 +3122,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3993,9 +3993,9 @@ dependencies = [ [[package]] name = "qp-wormhole-aggregator" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128197d45244b09c2a74e7741dc738e99ec9e6e962e130141cfb5a039d90a05c" +checksum = "04272fea9dbfbfa7798c3810b2c6992a51d3ea64dfe9865fc551e7d6beee1849" dependencies = [ "anyhow", "hex", @@ -4013,9 +4013,9 @@ dependencies = [ [[package]] name = "qp-wormhole-circuit" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d07dc178b68cb1ba21afe953d42a9f3c35aac2da88452d15f6bc6d5354ff665" +checksum = "f0095585d57804e1c92c0589e1d6cc782d54e0395e16b365c25ccdcaf65d9976" dependencies = [ "anyhow", "hex", @@ -4026,18 +4026,18 @@ dependencies = [ [[package]] name = "qp-wormhole-inputs" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed52f1c97996071aa3442537e6cd34a964568d7cec3dfd2a19c008aefc65a69" +checksum = "cbda85b94cac83a3748c5629976f599b6194b6e7d6225e928c9160bf407281cf" dependencies = [ "anyhow", ] [[package]] name = "qp-wormhole-prover" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ae4a1eaa8549ac5471b39aa48325ad645bf0b446985606719f6dd4f67e87f08" +checksum = "1bd9c12cd39356e6d68707369f414f123b82ef57cfd51f9fed2551cec1f202c9" dependencies = [ "anyhow", "qp-plonky2", @@ -4048,9 +4048,9 @@ dependencies = [ [[package]] name = "qp-wormhole-verifier" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391aa040d915295504bd2675be8d140fcbb639dbfe7fe033de604169c185d7f6" +checksum = "b8eed9ab36c6c49fff1ee882ff13d5ea0e2cf6022eee16386265cd5d2c351047" dependencies = [ "anyhow", "qp-plonky2-verifier", @@ -4059,9 +4059,9 @@ dependencies = [ [[package]] name = "qp-zk-circuits-common" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8259c977a1f275fe4c56a85b8bca4d23a4909cbf30601d850380672a58a4bf5c" +checksum = "deba700d52da41d59ebd9fb9f73e6055fa37d6276868d62baeeb52b4bd40e03a" dependencies = [ "anyhow", "hex", @@ -4170,7 +4170,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -4462,7 +4462,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5972,7 +5972,7 @@ dependencies = [ "getrandom 0.4.1", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -6891,7 +6891,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 80c3d0f..c1d24bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,12 +79,12 @@ subxt-metadata = "0.43.0" # ZK proof generation anyhow = "1.0" -qp-wormhole-circuit = { version = "1.0.5", default-features = false, features = ["std"] } -qp-wormhole-prover = { version = "1.0.5", default-features = false, features = ["std"] } -qp-wormhole-verifier = { version = "1.0.5", default-features = false, features = ["std"] } -qp-wormhole-aggregator = { version = "1.0.5", default-features = false, features = ["rayon", "std"] } -qp-wormhole-inputs = { version = "1.0.5", default-features = false, features = ["std"] } -qp-zk-circuits-common = { version = "1.0.5", default-features = false, features = ["std"] } +qp-wormhole-circuit = { version = "1.0.6", default-features = false, features = ["std"] } +qp-wormhole-prover = { version = "1.0.6", default-features = false, features = ["std"] } +qp-wormhole-verifier = { version = "1.0.6", default-features = false, features = ["std"] } +qp-wormhole-aggregator = { version = "1.0.6", default-features = false, features = ["rayon", "std"] } +qp-wormhole-inputs = { version = "1.0.6", default-features = false, features = ["std"] } +qp-zk-circuits-common = { version = "1.0.6", default-features = false, features = ["std"] } qp-plonky2 = { version = "1.1.3", default-features = false, features = ["rand", "std"] } [dev-dependencies] diff --git a/generated-bins/aggregated_common.bin b/generated-bins/aggregated_common.bin new file mode 100644 index 0000000000000000000000000000000000000000..11210063d89e1065f21a990777bae47b94e0d371 GIT binary patch literal 1353 zcmeBYfPerf%><=W(D)osJ|iPDl*Iz2WuUYGkY;~ zJ4?q|clUO-DytdJJ%96NRCmW8#bX=#r_OG^eZ!?nprelIU~b96?bgN&GZds$W-MzF z4O{(d<`ZAlGrIDtSyoH6PLG{`^U<7F2l8$i+>PFQKyCr^bKRQQnG=`awN$Ioz4!F` zgI6yOe2v(7s>E|no=2+L_Qms#ge?(@ReZ$wd5fp_`%S*fgafMPH~hKIt7x9#D_AE{ zxpaLazeZ|ul!1om^$vNHCz7&OdN-YH7U(EE6G%O@saMv{xgb+_O7Mjfjr%K{qau=& zrq%krciYwBI75za$ClF{3^z@$GdgtCImBjl?ZNNWqWOw3mMqoq0IMbQi-VYj>+te+s-9vZRi9SRUW{ z;?kT2y0a`C_pRG}Ze!|~_wU$K4Uhe~(6G}@A?EqfUxK2KI%daS5csL=7&MQe>tMFY z>%V7S9zOJ&EAO5`<}}SmiAg%a^KxSMwJN@A(3s9_A9~)==ezeoziZ_|hur5d9yV`Z zy~Xy!oSRRVuKLk@{owMWcaHbmxccY8gZ6)Cx>UrgSmspg;-Du4+OY5V~lGhT1WG9$u^IuFbnqKU6 ztf=YYA90(IFWYku4hg91hEdErcm~r23@<-Ls$X-o_hjWy) zM3yM{iBwoy3O%23yF6(1yQcyZf@2qPg&r|C<%A_{95gIFgVcfY0xVx}0onXezCDlz z0YM;E0<#zxgn+ajlnqMbAoVaH0%d^m2+Vv?5dzEXFdAkThz}EEgX#sT2LYhj0{{R2 ze-C0n089ofhavO!ZlqK@#%%Qujd_??{W$>HibTB@BH|^zJC7sB~c9Nbah^ zVbWuI70SP>J_^VW0f#q#TGod18ai+`nJPvI6_<= z{C?U=d}vL!YJXzV%g{GPvWfed^(EeV-KpdS?npG9FRi}dgsG!iR^l~o#d~V7m*lT7 zmqK4cxi^I%9#?A^pqAayULvI{JI}})y;A9txW8OX{nfWeK1fCFXOh*yv2S1NfAsk9 zKo}N1v;?5A**sz>_tWoS4r*s~>C5`UI`pl|Wy#ayTI)_AR#9*173248tL}uPs7f!O zGbjNYaWZ!i$_D^54V^Th5^v1AK<=W(D)osJ|iPDl*Iz2WuUYGkY*~yvT(b#F~bZ6DU}(^T13NE|C;&4SM`jp z{A!lfQmxZt=ihuZ=hcC{TLyQd_a2a2!2DddCU)k;<##RBYIN^Cz5d|UivwRHcAhHn zoRjB~YPNmxydz;tgklvRF@E0S>HU6_?=seQbCFNQ3sBOaE=x4yVEXMyf43&(xy zHlN#=`sMvQ_Ef`Te=aoabW@0Ve)N~1=%bF=u@?k>DmwnU{wT{pQNM zXOKBf^HE}wPVl^(*nO>v?;13wGuwxrcl7!0ebDb(dC(#EIgE$R+gER~{V?a|)1|9^ zG+#fs{OFzIJvXlYdGMh9-t*WQL9`?&iu68$Cv&_=^sI%m?1R>c8X4?E06O5)8dmSrky7))jCgjVv zu1%H`xdX~XXQ*f|sOos~*nV+$&?m0cxi#@K3^KlUzdx^9b#=l@*}}^*_7h7iE95T~ z`WbqZIPl2u@qAC3Hm|xT=*uD1wg-zpl__T2x10P?H8iqUQ{mwpB`uL93VtFL)|Nug zXWT9iTK(>+z=Yt~MO>jr%uP9A2^j|sOV1#6pd1NH|NKz4J(4~VC>xa7xPce|6aqOj literal 0 HcmV?d00001 diff --git a/generated-bins/config.json b/generated-bins/config.json new file mode 100644 index 0000000..6e09f7b --- /dev/null +++ b/generated-bins/config.json @@ -0,0 +1,12 @@ +{ + "branching_factor": 16, + "depth": 1, + "num_leaf_proofs": 16, + "hashes": { + "common": "672689a87e8ed780337c0752ebc7fd1db6a63611fbd59b4ad0cbe4a4d97edcf2", + "verifier": "bb017485b12fb9c6d0b5c3db8b68f417bd3f75b2d5f3a2ea5fe12b6244233372", + "prover": "78c114c7290b04bac00551a590fd652f98194653b10ac4e11b0c0ddd5c7c0976", + "aggregated_common": "af4461081f6fb527d2b9ffb74479a133ed8b92cdd3554b46adc481a0dfc38b5d", + "aggregated_verifier": "9895c3f86682fa59cb18b7e635f0e8ba563c8445bf4b58bb77b97dcf52ee5c42" + } +} \ No newline at end of file diff --git a/generated-bins/verifier.bin b/generated-bins/verifier.bin new file mode 100644 index 0000000000000000000000000000000000000000..21c3030681263b6f3d1ddb825623887a263b9629 GIT binary patch literal 552 zcmV+@0@wWn00000000116!d*;e7(&YU(oISZ=oY>!>}^>%XgWZcjlDeX&~NQyEBY3FWI}d39GZKmPW_(fTmTE%Uq<; z)%14d1PRX@3;*VB~1hp|s@lE;8d^2W3zuS*8&R$nSPzH}6_{~mTYdf!C$IC`pr z`StrA!bE$S16x*RSU}7WhKBfxnD-Omany43fv(`(f{|6uM#yS<`h| zoht-yv({x!fPZC$Wp1>C>t@rSNUiUuJ_W1rk;PFe{5goC<0?p!L|D=lhYZY8$q&W= literal 0 HcmV?d00001 diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index 46a818c..e7d1dfd 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -2541,6 +2541,36 @@ mod tests { // Ensure VOLUME_FEE_BPS matches expected value (10 bps = 0.1%) assert_eq!(VOLUME_FEE_BPS, 10); } + + #[test] + fn test_aggregation_config_deserialization_matches_upstream_format() { + // This test verifies that our local AggregationConfig struct can deserialize + // the same JSON format that the upstream CircuitBinsConfig produces. + // If the upstream adds/removes/renames fields, this test will catch it. + let json = r#"{ + "branching_factor": 8, + "depth": 1, + "num_leaf_proofs": 8, + "hashes": { + "common": "aabbcc", + "verifier": "ddeeff", + "prover": "112233", + "aggregated_common": "445566", + "aggregated_verifier": "778899" + } + }"#; + + let config: AggregationConfig = serde_json::from_str(json).unwrap(); + assert_eq!(config.branching_factor, 8); + assert_eq!(config.depth, 1); + assert_eq!(config.num_leaf_proofs, 8); + + let hashes = config.hashes.unwrap(); + assert_eq!(hashes.prover.as_deref(), Some("112233")); + assert_eq!(hashes.aggregated_common.as_deref(), Some("445566")); + assert_eq!(hashes.aggregated_verifier.as_deref(), Some("778899")); + } + fn mk_accounts(n: usize) -> Vec<[u8; 32]> { (0..n) .map(|i| { From fc1f09dfe7f964d80be5ee4c37019f9eb350a346 Mon Sep 17 00:00:00 2001 From: illuzen Date: Mon, 16 Feb 2026 19:48:03 +0800 Subject: [PATCH 25/26] flatten aggregation --- src/cli/mod.rs | 35 ++--- src/cli/wormhole.rs | 259 +++++++++++++++++----------------- tests/wormhole_integration.rs | 19 +-- 3 files changed, 146 insertions(+), 167 deletions(-) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 79149d3..5133ac4 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -293,13 +293,9 @@ pub enum DeveloperCommands { #[arg(long, default_value = "../chain")] chain_path: String, - /// Branching factor for aggregation tree (number of proofs aggregated at each level) + /// Number of leaf proofs aggregated into a single proof #[arg(long)] - branching_factor: usize, - - /// Depth of the aggregation tree (num_leaf_proofs = branching_factor^depth) - #[arg(long)] - depth: u32, + num_leaf_proofs: usize, /// Skip copying to chain directory #[arg(long)] @@ -558,18 +554,9 @@ pub async fn handle_developer_command(command: DeveloperCommands) -> crate::erro DeveloperCommands::BuildCircuits { circuits_path, chain_path, - branching_factor, - depth, + num_leaf_proofs, skip_chain, - } => - build_wormhole_circuits( - &circuits_path, - &chain_path, - branching_factor, - depth, - skip_chain, - ) - .await, + } => build_wormhole_circuits(&circuits_path, &chain_path, num_leaf_proofs, skip_chain).await, } } @@ -577,19 +564,12 @@ pub async fn handle_developer_command(command: DeveloperCommands) -> crate::erro async fn build_wormhole_circuits( circuits_path: &str, chain_path: &str, - branching_factor: usize, - depth: u32, + num_leaf_proofs: usize, skip_chain: bool, ) -> crate::error::Result<()> { use std::{path::Path, process::Command}; - let num_leaf_proofs = branching_factor.pow(depth); - log_print!( - "🔧 Building ZK circuit binaries (branching_factor={}, depth={}, max_proofs={})", - branching_factor, - depth, - num_leaf_proofs - ); + log_print!("Building ZK circuit binaries (num_leaf_proofs={})", num_leaf_proofs); log_print!(""); let circuits_dir = Path::new(circuits_path); @@ -626,7 +606,7 @@ async fn build_wormhole_circuits( log_print!("Step 2/4: Generating circuit binaries (this may take a while)..."); let builder_path = circuits_dir.join("target/release/qp-wormhole-circuit-builder"); let run_output = Command::new(&builder_path) - .args(["--branching-factor", &branching_factor.to_string(), "--depth", &depth.to_string()]) + .args(["--num-leaf-proofs", &num_leaf_proofs.to_string()]) .current_dir(circuits_dir) .output() .map_err(|e| { @@ -651,6 +631,7 @@ async fn build_wormhole_circuits( "common.bin", "verifier.bin", "prover.bin", + "dummy_proof.bin", "aggregated_common.bin", "aggregated_verifier.bin", "config.json", diff --git a/src/cli/wormhole.rs b/src/cli/wormhole.rs index e7d1dfd..4d198f8 100644 --- a/src/cli/wormhole.rs +++ b/src/cli/wormhole.rs @@ -59,14 +59,13 @@ pub struct BinaryHashes { pub prover: Option, pub aggregated_common: Option, pub aggregated_verifier: Option, + pub dummy_proof: Option, } /// Aggregation config loaded from generated-bins/config.json. /// Must match the CircuitBinsConfig struct in qp-wormhole-aggregator/src/config.rs #[derive(Debug, Clone, serde::Deserialize)] pub struct AggregationConfig { - pub branching_factor: usize, - pub depth: u32, pub num_leaf_proofs: usize, #[serde(default)] pub hashes: Option, @@ -115,6 +114,7 @@ impl AggregationConfig { ("aggregated_common.bin", &stored_hashes.aggregated_common), ("aggregated_verifier.bin", &stored_hashes.aggregated_verifier), ("prover.bin", &stored_hashes.prover), + ("dummy_proof.bin", &stored_hashes.dummy_proof), ]; for (filename, expected_hash) in checks { if let Some(ref expected) = expected_hash { @@ -327,77 +327,83 @@ pub fn compute_random_output_assignments( let target_amounts_u128 = random_partition(total_output as u128, num_targets, min_per_target); let target_amounts: Vec = target_amounts_u128.iter().map(|&x| x as u32).collect(); - // Step 3: Assign outputs to proofs using a greedy algorithm - // Each proof can have at most 2 outputs to different targets + // Step 3: Assign outputs to proofs. + // Each proof can have at most 2 outputs to different targets. // - // Strategy: For each proof, we try to split across two targets if possible - // to maximize mixing. We process targets in shuffled order. + // Strategy: + // Pass 1 - Guarantee every target gets at least one output slot by round-robin + // assigning each target as output_1 of successive proofs. + // Pass 2 - Fill remaining capacity (output_2 slots and any leftover amounts) + // greedily from targets that still have remaining allocation. + // + // This ensures every target address appears in at least one proof output, + // which is critical for the multiround flow where each target is a next-round + // wormhole address that must receive minted tokens. let mut rng = rand::rng(); - let mut assignments = Vec::with_capacity(num_proofs); - - // Shuffle target indices for random assignment order - let mut target_order: Vec = (0..num_targets).collect(); - target_order.shuffle(&mut rng); - // Track remaining needs per target (in original index order) + // Track remaining needs per target let mut target_remaining: Vec = target_amounts.clone(); - for &proof_output in proof_outputs.iter() { - let mut remaining = proof_output; - let mut output_1_amount = 0u32; - let mut output_1_account = [0u8; 32]; - let mut output_2_amount = 0u32; - let mut output_2_account = [0u8; 32]; - let mut outputs_assigned = 0; - - // Try to assign to targets in shuffled order - for &tidx in &target_order { - if remaining == 0 { - break; - } - if outputs_assigned >= 2 { - // Already have 2 outputs, add remainder to output_1 - output_1_amount += remaining; - remaining = 0; - break; - } - if target_remaining[tidx] == 0 { - continue; - } - - let assign = remaining.min(target_remaining[tidx]); - if assign == 0 { - continue; - } - - if outputs_assigned == 0 { - output_1_amount = assign; - output_1_account = target_accounts[tidx]; - } else { - output_2_amount = assign; - output_2_account = target_accounts[tidx]; - } + // Pre-allocate assignments with output_1 = full proof output, output_2 = 0 + let mut assignments: Vec = proof_outputs + .iter() + .map(|&po| ProofOutputAssignment { + output_amount_1: po, + exit_account_1: [0u8; 32], + output_amount_2: 0, + exit_account_2: [0u8; 32], + }) + .collect(); - remaining -= assign; + // Pass 1: Round-robin assign each target to a proof's output_1. + // If num_targets <= num_proofs, each target gets its own proof. + // If num_targets > num_proofs, later targets share proofs via output_2. + let mut shuffled_targets: Vec = (0..num_targets).collect(); + shuffled_targets.shuffle(&mut rng); + + for (assign_idx, &tidx) in shuffled_targets.iter().enumerate() { + let proof_idx = assign_idx % num_proofs; + let assignment = &mut assignments[proof_idx]; + + if assignment.exit_account_1 == [0u8; 32] { + // First target for this proof -> use output_1 + let assign = assignment.output_amount_1.min(target_remaining[tidx]); + assignment.exit_account_1 = target_accounts[tidx]; + // We'll fix up the exact amounts in pass 2; for now just mark the account + assignment.output_amount_1 = assign; + target_remaining[tidx] -= assign; + } else if assignment.exit_account_2 == [0u8; 32] { + // Second target for this proof -> use output_2 + let avail = proof_outputs[proof_idx].saturating_sub(assignment.output_amount_1); + let assign = avail.min(target_remaining[tidx]); + assignment.exit_account_2 = target_accounts[tidx]; + assignment.output_amount_2 = assign; target_remaining[tidx] -= assign; - outputs_assigned += 1; } + // If both slots taken, skip (shouldn't happen when num_targets <= 2*num_proofs) + } - // If we still have remaining (shouldn't happen normally), add to output_1 - if remaining > 0 { - output_1_amount += remaining; + // Pass 2: Distribute any remaining target allocations into available proof outputs. + // Also ensure each proof's output_1 + output_2 == proof_outputs[i]. + for proof_idx in 0..num_proofs { + let total_proof_output = proof_outputs[proof_idx]; + let current_sum = + assignments[proof_idx].output_amount_1 + assignments[proof_idx].output_amount_2; + let mut shortfall = total_proof_output.saturating_sub(current_sum); + + if shortfall > 0 { + // Add shortfall to output_1 (its account is already set) + assignments[proof_idx].output_amount_1 += shortfall; + shortfall = 0; } - assignments.push(ProofOutputAssignment { - output_amount_1: output_1_amount, - exit_account_1: output_1_account, - output_amount_2: output_2_amount, - exit_account_2: output_2_account, - }); + // If output_1_account is still [0;32] (shouldn't happen), assign first target as fallback + if assignments[proof_idx].exit_account_1 == [0u8; 32] && num_targets > 0 { + assignments[proof_idx].exit_account_1 = target_accounts[0]; + } - // Re-shuffle target order for next proof to increase mixing - target_order.shuffle(&mut rng); + let _ = shortfall; // suppress unused warning } assignments @@ -772,6 +778,7 @@ async fn aggregate_proofs( output_file: String, ) -> crate::error::Result<()> { use qp_wormhole_aggregator::aggregator::WormholeProofAggregator; + use qp_zk_circuits_common::aggregation::AggregationConfig as AggConfig; use std::path::Path; @@ -801,7 +808,8 @@ async fn aggregate_proofs( // This also generates the padding (dummy) proofs needed log_print!(" Loading aggregator and generating {} dummy proofs...", num_padding_proofs); - let mut aggregator = WormholeProofAggregator::from_prebuilt_dir(bins_dir, proof_files.len()) + let aggr_config = AggConfig::new(agg_config.num_leaf_proofs); + let mut aggregator = WormholeProofAggregator::from_prebuilt_dir(bins_dir, aggr_config) .map_err(|e| { crate::error::QuantusError::Generic(format!( "Failed to load aggregator from pre-built bins: {}", @@ -809,12 +817,7 @@ async fn aggregate_proofs( )) })?; - log_verbose!( - "Aggregation config: branching_factor={}, depth={}, num_leaf_proofs={}", - aggregator.config.tree_branching_factor, - aggregator.config.tree_depth, - aggregator.config.num_leaf_proofs - ); + log_verbose!("Aggregation config: num_leaf_proofs={}", aggregator.config.num_leaf_proofs); let common_data = aggregator.leaf_circuit_data.common.clone(); // Load and add proofs using helper function @@ -1282,11 +1285,7 @@ fn print_multiround_config( ); log_print!(" Proofs per round: {}", config.num_proofs); log_print!(" Rounds: {}", config.rounds); - log_print!( - " Aggregation: branching_factor={}, depth={}", - agg_config.branching_factor, - agg_config.depth - ); + log_print!(" Aggregation: num_leaf_proofs={}", agg_config.num_leaf_proofs); log_print!(" Output directory: {}", config.output_dir); log_print!(" Keep files: {}", config.keep_files); log_print!(""); @@ -1300,7 +1299,10 @@ fn print_multiround_config( log_print!(""); } -/// Execute initial transfers from wallet to wormhole addresses (round 1 only) +/// Execute initial transfers from wallet to wormhole addresses (round 1 only). +/// +/// Sends all transfers in a single batched extrinsic using `utility.batch()`, +/// then parses the `NativeTransferred` events to extract transfer info for proof generation. async fn execute_initial_transfers( quantus_client: &QuantusClient, wallet: &MultiroundWalletContext, @@ -1309,8 +1311,11 @@ async fn execute_initial_transfers( num_proofs: usize, ) -> crate::error::Result> { use colored::Colorize; + use quantus_node::api::runtime_types::{ + pallet_balances::pallet::Call as BalancesCall, quantus_runtime::RuntimeCall, + }; - log_print!("{}", "Step 1: Sending transfers to wormhole addresses...".bright_yellow()); + log_print!("{}", "Step 1: Sending batched transfer to wormhole addresses...".bright_yellow()); // Randomly partition the total amount among proofs // Each partition must meet the on-chain minimum transfer amount @@ -1321,79 +1326,81 @@ async fn execute_initial_transfers( log_print!(" Proof {}: {} ({})", i + 1, amt, format_balance(amt)); } - let pb = ProgressBar::new(num_proofs as u64); - pb.set_style( - ProgressStyle::default_bar() - .template("{spinner:.green} [{bar:40.cyan/blue}] {pos}/{len} {msg}") - .unwrap() - .progress_chars("#>-"), - ); + // Build batch of transfer calls + let mut calls = Vec::with_capacity(num_proofs); + for (i, secret) in secrets.iter().enumerate() { + let wormhole_address = SubxtAccountId(secret.address); + let transfer_call = RuntimeCall::Balances(BalancesCall::transfer_allow_death { + dest: subxt::ext::subxt_core::utils::MultiAddress::Id(wormhole_address), + value: partition_amounts[i], + }); + calls.push(transfer_call); + } - let client = quantus_client.client(); - let mut transfers = Vec::new(); + let batch_tx = quantus_node::api::tx().utility().batch(calls); - for (i, secret) in secrets.iter().enumerate() { - pb.set_message(format!("Transfer {}/{}", i + 1, num_proofs)); + let quantum_keypair = QuantumKeyPair { + public_key: wallet.keypair.public_key.clone(), + private_key: wallet.keypair.private_key.clone(), + }; - let wormhole_address = SubxtAccountId(secret.address); - let transfer_amount = partition_amounts[i]; - - // Use standard Balances::transfer_allow_death -- the chain's - // WormholeProofRecorderExtension automatically records a transfer proof - // and emits NativeTransferred for any balance transfer. - let transfer_tx = quantus_node::api::tx().balances().transfer_allow_death( - subxt::ext::subxt_core::utils::MultiAddress::Id(wormhole_address.clone()), - transfer_amount, - ); + log_print!(" Submitting batch of {} transfers...", num_proofs); - let quantum_keypair = QuantumKeyPair { - public_key: wallet.keypair.public_key.clone(), - private_key: wallet.keypair.private_key.clone(), - }; + submit_transaction( + quantus_client, + &quantum_keypair, + batch_tx, + None, + ExecutionMode { finalized: false, wait_for_transaction: true }, + ) + .await + .map_err(|e| crate::error::QuantusError::Generic(format!("Batch transfer failed: {}", e)))?; - submit_transaction( - quantus_client, - &quantum_keypair, - transfer_tx, - None, - ExecutionMode { finalized: false, wait_for_transaction: true }, - ) + // Get the block and find all NativeTransferred events + let client = quantus_client.client(); + let block = at_best_block(quantus_client) .await - .map_err(|e| crate::error::QuantusError::Generic(format!("Transfer failed: {}", e)))?; - - // Get the block and find our event - let block = at_best_block(quantus_client).await.map_err(|e| { - crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)) - })?; - let block_hash = block.hash(); + .map_err(|e| crate::error::QuantusError::Generic(format!("Failed to get block: {}", e)))?; + let block_hash = block.hash(); - let events_api = client.events().at(block_hash).await.map_err(|e| { + let events_api = + client.events().at(block_hash).await.map_err(|e| { crate::error::QuantusError::Generic(format!("Failed to get events: {}", e)) })?; - // Find the NativeTransferred event emitted by the WormholeProofRecorderExtension + // Match each secret's wormhole address to its NativeTransferred event + let funding_account: SubxtAccountId = SubxtAccountId(wallet.keypair.to_account_id_32().into()); + let mut transfers = Vec::with_capacity(num_proofs); + + for (i, secret) in secrets.iter().enumerate() { let event = events_api .find::() .find(|e| if let Ok(evt) = e { evt.to.0 == secret.address } else { false }) .ok_or_else(|| { - crate::error::QuantusError::Generic("No matching transfer event found".to_string()) + crate::error::QuantusError::Generic(format!( + "No NativeTransferred event found for wormhole address {} (proof {})", + hex::encode(secret.address), + i + 1 + )) })? .map_err(|e| { crate::error::QuantusError::Generic(format!("Event decode error: {}", e)) })?; - let funding_account_bytes = wallet.keypair.to_account_id_32(); transfers.push(TransferInfo { block_hash, transfer_count: event.transfer_count, - amount: transfer_amount, - wormhole_address, - funding_account: SubxtAccountId(funding_account_bytes.into()), + amount: partition_amounts[i], + wormhole_address: SubxtAccountId(secret.address), + funding_account: funding_account.clone(), }); - - pb.inc(1); } - pb.finish_with_message("Transfers complete"); + + log_success!( + " {} transfers submitted in a single batch (block {})", + num_proofs, + hex::encode(block_hash.0) + ); Ok(transfers) } @@ -2541,15 +2548,13 @@ mod tests { // Ensure VOLUME_FEE_BPS matches expected value (10 bps = 0.1%) assert_eq!(VOLUME_FEE_BPS, 10); } - + #[test] fn test_aggregation_config_deserialization_matches_upstream_format() { // This test verifies that our local AggregationConfig struct can deserialize // the same JSON format that the upstream CircuitBinsConfig produces. // If the upstream adds/removes/renames fields, this test will catch it. let json = r#"{ - "branching_factor": 8, - "depth": 1, "num_leaf_proofs": 8, "hashes": { "common": "aabbcc", @@ -2561,8 +2566,6 @@ mod tests { }"#; let config: AggregationConfig = serde_json::from_str(json).unwrap(); - assert_eq!(config.branching_factor, 8); - assert_eq!(config.depth, 1); assert_eq!(config.num_leaf_proofs, 8); let hashes = config.hashes.unwrap(); diff --git a/tests/wormhole_integration.rs b/tests/wormhole_integration.rs index 60e8653..f1c198d 100644 --- a/tests/wormhole_integration.rs +++ b/tests/wormhole_integration.rs @@ -500,30 +500,26 @@ async fn submit_single_proof_for_verification( /// Aggregate multiple proofs into one fn aggregate_proofs( proof_contexts: Vec, - depth: usize, - branching_factor: usize, + num_leaf_proofs: usize, ) -> Result { use qp_wormhole_aggregator::{ - aggregator::WormholeProofAggregator, circuits::tree::TreeAggregationConfig, + aggregator::WormholeProofAggregator, circuits::tree::AggregationConfig, }; println!( - " Aggregating {} proofs (depth={}, branching_factor={})...", + " Aggregating {} proofs (num_leaf_proofs={})...", proof_contexts.len(), - depth, - branching_factor + num_leaf_proofs, ); let config = CircuitConfig::standard_recursion_zk_config(); - let aggregation_config = TreeAggregationConfig::new(branching_factor, depth as u32); + let aggregation_config = AggregationConfig::new(num_leaf_proofs); if proof_contexts.len() > aggregation_config.num_leaf_proofs { return Err(format!( - "Too many proofs: {} provided, max {} for depth={} branching_factor={}", + "Too many proofs: {} provided, max {}", proof_contexts.len(), aggregation_config.num_leaf_proofs, - depth, - branching_factor )); } @@ -844,8 +840,7 @@ async fn test_aggregated_proof_on_chain_verification() { println!("\n4. Aggregating {} proofs...", proof_contexts.len()); let aggregated_context = aggregate_proofs( proof_contexts, - 1, // depth - 2, // branching_factor (2^1 = 2 max proofs) + 2, // num_leaf_proofs ) .expect("Failed to aggregate proofs"); From b311e0938273f4b47860b03fec872d070841cb1a Mon Sep 17 00:00:00 2001 From: illuzen Date: Tue, 17 Feb 2026 12:18:57 +0800 Subject: [PATCH 26/26] ci cleanup --- Cargo.lock | 25 +++++++++++++------------ Cargo.toml | 12 ++++++------ tests/wormhole_integration.rs | 7 +++---- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c723444..4a5aa4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3993,9 +3993,9 @@ dependencies = [ [[package]] name = "qp-wormhole-aggregator" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04272fea9dbfbfa7798c3810b2c6992a51d3ea64dfe9865fc551e7d6beee1849" +checksum = "bad3d3f37af4748e635f9197b2145cf4d218b97ad361e6b696724e3ddbb4e12a" dependencies = [ "anyhow", "hex", @@ -4013,9 +4013,9 @@ dependencies = [ [[package]] name = "qp-wormhole-circuit" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0095585d57804e1c92c0589e1d6cc782d54e0395e16b365c25ccdcaf65d9976" +checksum = "f7cdfba4fd293063a3e9eb964e2afb58673e9a7fd6d4edb0484783e0ed600927" dependencies = [ "anyhow", "hex", @@ -4026,18 +4026,18 @@ dependencies = [ [[package]] name = "qp-wormhole-inputs" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbda85b94cac83a3748c5629976f599b6194b6e7d6225e928c9160bf407281cf" +checksum = "53ad195630b070fc8cd9d89c55a951abaae9694434793bc87f5ab3045ded7108" dependencies = [ "anyhow", ] [[package]] name = "qp-wormhole-prover" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd9c12cd39356e6d68707369f414f123b82ef57cfd51f9fed2551cec1f202c9" +checksum = "d244e8514279f65d25f15ed5a6e6464905ac5276724a9233574696e11a461c3a" dependencies = [ "anyhow", "qp-plonky2", @@ -4048,9 +4048,9 @@ dependencies = [ [[package]] name = "qp-wormhole-verifier" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8eed9ab36c6c49fff1ee882ff13d5ea0e2cf6022eee16386265cd5d2c351047" +checksum = "f9e95153853ceceeba61295ca5f1316d12bde37677b0c1e7f0539d815f627645" dependencies = [ "anyhow", "qp-plonky2-verifier", @@ -4059,15 +4059,16 @@ dependencies = [ [[package]] name = "qp-zk-circuits-common" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deba700d52da41d59ebd9fb9f73e6055fa37d6276868d62baeeb52b4bd40e03a" +checksum = "d45c3d80adc2aecbcf27902569d3ec291f5f83e9d7d17ad12530f45102963faa" dependencies = [ "anyhow", "hex", "qp-plonky2", "qp-poseidon-core", "qp-wormhole-inputs", + "rand 0.8.5", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index c1d24bd..14ac8fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,12 +79,12 @@ subxt-metadata = "0.43.0" # ZK proof generation anyhow = "1.0" -qp-wormhole-circuit = { version = "1.0.6", default-features = false, features = ["std"] } -qp-wormhole-prover = { version = "1.0.6", default-features = false, features = ["std"] } -qp-wormhole-verifier = { version = "1.0.6", default-features = false, features = ["std"] } -qp-wormhole-aggregator = { version = "1.0.6", default-features = false, features = ["rayon", "std"] } -qp-wormhole-inputs = { version = "1.0.6", default-features = false, features = ["std"] } -qp-zk-circuits-common = { version = "1.0.6", default-features = false, features = ["std"] } +qp-wormhole-circuit = { version = "1.0.7", default-features = false, features = ["std"] } +qp-wormhole-prover = { version = "1.0.7", default-features = false, features = ["std"] } +qp-wormhole-verifier = { version = "1.0.7", default-features = false, features = ["std"] } +qp-wormhole-aggregator = { version = "1.0.7", default-features = false, features = ["rayon", "std"] } +qp-wormhole-inputs = { version = "1.0.7", default-features = false, features = ["std"] } +qp-zk-circuits-common = { version = "1.0.7", default-features = false, features = ["std"] } qp-plonky2 = { version = "1.1.3", default-features = false, features = ["rand", "std"] } [dev-dependencies] diff --git a/tests/wormhole_integration.rs b/tests/wormhole_integration.rs index f1c198d..1353029 100644 --- a/tests/wormhole_integration.rs +++ b/tests/wormhole_integration.rs @@ -502,9 +502,8 @@ fn aggregate_proofs( proof_contexts: Vec, num_leaf_proofs: usize, ) -> Result { - use qp_wormhole_aggregator::{ - aggregator::WormholeProofAggregator, circuits::tree::AggregationConfig, - }; + use qp_wormhole_aggregator::aggregator::WormholeProofAggregator; + use qp_zk_circuits_common::aggregation::AggregationConfig; println!( " Aggregating {} proofs (num_leaf_proofs={})...", @@ -1137,7 +1136,7 @@ async fn test_full_wormhole_workflow() { // Step 3: Aggregate and verify println!("\n--- Step 3: Aggregation ---"); let aggregated = - aggregate_proofs(proofs_for_aggregation, 1, 2).expect("Failed to aggregate proofs"); + aggregate_proofs(proofs_for_aggregation, 2).expect("Failed to aggregate proofs"); println!(" Verifying aggregated proof on-chain..."); submit_aggregated_proof_for_verification(&quantus_client, aggregated.proof_bytes)