diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a93461a3..1e41c488 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,12 +33,18 @@ jobs: - uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # stable with: toolchain: stable + targets: wasm32-unknown-unknown - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 - name: cargo build run: cargo build --workspace --all-targets --all-features + - name: cargo build (wasm32) + # Guards the wasm host bridge and its offline subxt surface, which the + # host-target build never compiles. + run: cargo build -p truapi-server --target wasm32-unknown-unknown --no-default-features + - name: cargo +nightly fmt --check run: cargo +nightly fmt --check diff --git a/.gitignore b/.gitignore index 620568d2..f0359297 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,10 @@ lerna-debug.log* node_modules target +# Local Bun side effects (repo lockfiles are npm/yarn) +bun.lock +bun.lockb + # Gradle (Android workspace at repo root) /.gradle/ /build/ @@ -55,6 +59,5 @@ js/packages/truapi/src/generated/ js/packages/truapi/dist/generated/ js/packages/truapi-host/src/generated/ js/packages/truapi-host/dist/generated/ -js/packages/truapi-host-wasm/src/generated/ -js/packages/truapi-host-wasm/dist/generated/ -js/packages/truapi-host-wasm/dist/wasm/ +js/packages/truapi-host/dist/wasm/ +js/packages/truapi-host-wasm/ diff --git a/.gitmodules b/.gitmodules index ffa7a3c9..dff6d927 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,7 @@ path = hosts/dotli url = https://github.com/paritytech/dotli-community branch = main +[submodule "hosts/ios"] + path = hosts/ios + url = https://github.com/paritytech/polkadot-app-ios-v2 + branch = codex/truapi-rust-core diff --git a/CLAUDE.md b/CLAUDE.md index d0df0ce5..46d8d44b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,6 +13,7 @@ rust/crates/ truapi-macros/ #[wire(id = N)] proc-macro truapi-platform/ Host syscall traits (storage, navigation, consent, ...) truapi-server/ Rust runtime hosts implement; ships as WASM (browser/node) + truapi-host-cli/ Headless pairing-host + signing-host CLIs that pair over the real People-chain statement store; local e2e signing-bot replacement js/packages/ truapi/ @parity/truapi TS package; generated TS lives under ignored paths truapi-host/ @parity/truapi-host: WASM-backed host runtime. Subpath entries: @@ -38,8 +39,10 @@ scripts/codegen.sh regenerate the TS client from the Rust crate - `truapi-server` WASM artifacts live under `js/packages/truapi-host/dist/wasm/web/` and are gitignored. Build them locally with `make wasm` (rerun whenever - `rust/crates/truapi-server/` changes); CI builds the bundle fresh from the - Rust source on every run. + `rust/crates/truapi-server/` changes). CI compiles the crate for + `wasm32-unknown-unknown` to guard the wasm bridge and its offline subxt + surface, but does not build or publish the packaged bundle; run `make wasm` + locally before relying on the browser host. ## Code style diff --git a/Cargo.lock b/Cargo.lock index 84faa731..85693598 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,7 +20,7 @@ checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -37,6 +37,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -99,6 +120,194 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1786b2e3832f6f0f7c8d62d5d5a282f6952a1ab99981c54cd52b6ac1d8f02df5" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "arrayvec 0.7.6", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.5", + "rayon", +] + +[[package]] +name = "ark-scale" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985c81a9c7b23a72f62b7b20686d5326d2a9956806f37de9ee35cb1238faf0c0" +dependencies = [ + "ark-serialize", + "ark-std", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "arrayvec 0.7.6", + "digest 0.10.7", + "num-bigint", + "rayon", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.6", + "rayon", +] + +[[package]] +name = "ark-transcript" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c1c928edb9d8ff24cb5dcb7651d3a98494fff3099eee95c2404cd813a9139f" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "digest 0.10.7", + "rand_core 0.6.4", + "sha3", +] + +[[package]] +name = "ark-vrf" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b9bd02dbd2f282fe742d51f681adb2745a79dc8a025bc8d16cac9b255d55bf7" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ff", + "ark-serialize", + "ark-std", + "digest 0.10.7", + "generic-array", + "rayon", + "sha2 0.10.9", + "w3f-ring-proof", + "zeroize", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -120,6 +329,48 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "askama" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac" +dependencies = [ + "askama_parser", + "basic-toml", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "askama_parser" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f" +dependencies = [ + "memchr", + "serde", + "serde_derive", + "winnow 0.7.15", +] + [[package]] name = "async-channel" version = "2.5.0" @@ -280,6 +531,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076" +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + [[package]] name = "base64" version = "0.22.1" @@ -292,6 +549,15 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "basic-toml" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" +dependencies = [ + "serde", +] + [[package]] name = "bip39" version = "2.2.2" @@ -299,6 +565,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90dbd31c98227229239363921e60fcf5e558e43ec69094d46fc4996f08d1d5bc" dependencies = [ "bitcoin_hashes", + "rand 0.8.6", + "rand_core 0.6.4", + "serde", + "unicode-normalization", ] [[package]] @@ -328,6 +598,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "blake2-rfc" version = "0.2.18" @@ -380,6 +659,19 @@ dependencies = [ "piper", ] +[[package]] +name = "bounded-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee8eddd066a8825ec5570528e6880471210fd5d88cb6abbe1cfdd51ca249c33" +dependencies = [ + "jam-codec", + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + [[package]] name = "bs58" version = "0.5.1" @@ -413,6 +705,38 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" +[[package]] +name = "camino" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "cast" version = "0.3.0" @@ -441,6 +765,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chacha20" version = "0.9.1" @@ -449,7 +779,18 @@ checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" dependencies = [ "cfg-if", "cipher", - "cpufeatures", + "cpufeatures 0.2.17", +] + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core 0.10.1", ] [[package]] @@ -619,6 +960,34 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -647,7 +1016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -659,7 +1028,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -689,7 +1058,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", @@ -709,6 +1078,47 @@ dependencies = [ "syn", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" + [[package]] name = "der" version = "0.7.10" @@ -831,12 +1241,24 @@ dependencies = [ "ed25519", "hashbrown 0.16.1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sha2 0.10.9", "subtle", "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.16.0" @@ -856,12 +1278,32 @@ dependencies = [ "generic-array", "group", "hkdf", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", ] +[[package]] +name = "enum-ordinalize" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f808d588c10e464ea6f7d3eaed500049eff30aaac103460f61828c2d65b3eb" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e528e2d34ba8a67a1a650b86beae8ef69fc5fdb638016f386b973226590432" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -908,7 +1350,7 @@ dependencies = [ "foldhash 0.2.0", "libm", "portable-atomic", - "siphasher", + "siphasher 1.0.3", ] [[package]] @@ -923,7 +1365,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -956,7 +1398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand", + "rand 0.8.6", "rustc-hex", "static_assertions", ] @@ -988,6 +1430,24 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "frame-decode" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88cda60c640572c970c544ba5879375a18ecfb2c47c617be8265830b63df193d" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-decode", + "scale-encode", + "scale-info", + "scale-info-legacy", + "scale-type-resolver", + "serde_yaml", + "sp-crypto-hashing", + "thiserror 2.0.18", +] + [[package]] name = "frame-metadata" version = "23.0.1" @@ -997,6 +1457,16 @@ dependencies = [ "cfg-if", "parity-scale-codec", "scale-info", + "serde", +] + +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", ] [[package]] @@ -1147,10 +1617,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", + "rand_core 0.10.1", "wasip2", "wasip3", + "wasm-bindgen", ] [[package]] @@ -1159,7 +1632,8 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea1015b5a70616b688dc230cfe50c8af89d972cb132d5a622814d29773b10b9" dependencies = [ - "rand_core", + "rand 0.8.6", + "rand_core 0.6.4", ] [[package]] @@ -1172,6 +1646,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + [[package]] name = "gloo-net" version = "0.6.0" @@ -1218,15 +1698,36 @@ dependencies = [ "web-sys", ] +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + [[package]] name = "group" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "ff", - "rand_core", - "subtle", + "ahash", + "allocator-api2", ] [[package]] @@ -1235,6 +1736,7 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ + "allocator-api2", "foldhash 0.1.5", ] @@ -1333,12 +1835,94 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + [[package]] name = "httparse" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +[[package]] +name = "hyper" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots 1.0.7", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + [[package]] name = "icu_collections" version = "2.2.0" @@ -1427,6 +2011,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -1507,12 +2097,27 @@ dependencies = [ "generic-array", ] +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -1528,6 +2133,34 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jam-codec" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb948eace373d99de60501a02fb17125d30ac632570de20dccc74370cdd611b9" +dependencies = [ + "arrayvec 0.7.6", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "jam-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "jam-codec-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319af585c4c8a6b5552a52b7787a1ab3e4d59df7614190b1f85b9b842488789d" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "jni" version = "0.21.1" @@ -1685,7 +2318,17 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", +] + +[[package]] +name = "keccak-hash" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1b8590eb6148af2ea2d75f38e7d29f5ca970d5a4df456b3ef19b8b415d0264" +dependencies = [ + "primitive-types", + "tiny-keccak", ] [[package]] @@ -1740,7 +2383,7 @@ dependencies = [ "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", - "rand", + "rand 0.8.6", "serde", "sha2 0.9.9", "typenum", @@ -1811,6 +2454,21 @@ dependencies = [ "hashbrown 0.16.1", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "memchr" version = "2.8.0" @@ -1825,7 +2483,7 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core", + "rand_core 0.6.4", "zeroize", ] @@ -1839,6 +2497,12 @@ dependencies = [ "walkdir", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" version = "1.2.1" @@ -1862,7 +2526,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" dependencies = [ - "rand", + "rand 0.8.6", ] [[package]] @@ -1871,6 +2535,16 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nom" version = "8.0.0" @@ -2026,6 +2700,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pbkdf2" version = "0.12.2" @@ -2097,6 +2777,12 @@ dependencies = [ "spki", ] +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "polling" version = "3.11.0" @@ -2117,7 +2803,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", "universal-hash", ] @@ -2129,7 +2815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", "universal-hash", ] @@ -2186,6 +2872,7 @@ dependencies = [ "fixed-hash", "impl-codec", "impl-serde", + "scale-info", "uint", ] @@ -2198,6 +2885,28 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -2207,6 +2916,62 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "bytes", + "getrandom 0.4.2", + "lru-slab", + "rand 0.10.2", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + [[package]] name = "quote" version = "1.0.45" @@ -2236,7 +3001,18 @@ checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20 0.10.1", + "getrandom 0.4.2", + "rand_core 0.10.1", ] [[package]] @@ -2246,7 +3022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2258,6 +3034,41 @@ dependencies = [ "getrandom 0.2.17", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -2267,6 +3078,61 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 1.0.7", +] + [[package]] name = "ring" version = "0.17.14" @@ -2348,6 +3214,7 @@ version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ + "web-time", "zeroize", ] @@ -2401,6 +3268,12 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "same-file" version = "1.0.6" @@ -2410,16 +3283,85 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scale-bits" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27243ab0d2d6235072b017839c5f0cd1a3b1ce45c0f7a715363b0c7d36c76c94" +dependencies = [ + "parity-scale-codec", + "scale-info", + "scale-type-resolver", + "serde", +] + +[[package]] +name = "scale-decode" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d6ed61699ad4d54101ab5a817169259b5b0efc08152f8632e61482d8a27ca3d" +dependencies = [ + "parity-scale-codec", + "primitive-types", + "scale-bits", + "scale-decode-derive", + "scale-type-resolver", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "scale-decode-derive" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65cb245f7fdb489e7ba43a616cbd34427fe3ba6fe0edc1d0d250085e6c84f3ec" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "scale-encode" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2a976d73564a59e482b74fd5d95f7518b79ca8c8ca5865398a4d629dd15ee50" +dependencies = [ + "parity-scale-codec", + "primitive-types", + "scale-bits", + "scale-encode-derive", + "scale-type-resolver", + "smallvec", + "thiserror 2.0.18", +] + +[[package]] +name = "scale-encode-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17020f2d59baabf2ddcdc20a4e567f8210baf089b8a8d4785f5fd5e716f92038" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "scale-info" version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" dependencies = [ + "bitvec", "cfg-if", "derive_more 1.0.0", "parity-scale-codec", "scale-info-derive", + "serde", ] [[package]] @@ -2434,6 +3376,63 @@ dependencies = [ "syn", ] +[[package]] +name = "scale-info-legacy" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d972ce93a4f81efc40fce251e992faf99ecb090c02bcbd3614e213991038c181" +dependencies = [ + "hashbrown 0.16.1", + "scale-type-resolver", + "serde", + "smallstr", + "smallvec", + "thiserror 2.0.18", + "yap", +] + +[[package]] +name = "scale-type-resolver" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb" +dependencies = [ + "scale-info", + "smallvec", +] + +[[package]] +name = "scale-typegen" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642d2f13f3fc9a34ea2c1e36142984eba78cd2405a61632492f8b52993e98879" +dependencies = [ + "proc-macro2", + "quote", + "scale-info", + "syn", + "thiserror 2.0.18", +] + +[[package]] +name = "scale-value" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3b64809a541e8d5a59f7a9d67cc700cdf5d7f907932a83a0afdedc90db07ccb" +dependencies = [ + "base58", + "blake2", + "either", + "parity-scale-codec", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-type-resolver", + "serde", + "thiserror 2.0.18", + "yap", +] + [[package]] name = "schannel" version = "0.1.29" @@ -2455,7 +3454,7 @@ dependencies = [ "curve25519-dalek", "getrandom_or_panic", "merlin", - "rand_core", + "rand_core 0.6.4", "serde_bytes", "sha2 0.10.9", "subtle", @@ -2468,6 +3467,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sec1" version = "0.7.3" @@ -2509,6 +3528,10 @@ name = "semver" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "send_wrapper" @@ -2578,6 +3601,31 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1" version = "0.10.6" @@ -2585,7 +3633,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -2597,7 +3645,7 @@ checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.9.0", "opaque-debug", ] @@ -2609,7 +3657,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -2654,6 +3702,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "siphasher" version = "1.0.3" @@ -2666,12 +3720,27 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +[[package]] +name = "smallstr" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862077b1e764f04c251fe82a2ef562fd78d7cadaeb072ca7c2bcaf7217b1ff3b" +dependencies = [ + "smallvec", +] + [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "smawk" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e2fb0f499abb4d162f2bedad68f5ef91a1682b5a03596ddb67efd37768d100" + [[package]] name = "smol" version = "2.0.2" @@ -2703,7 +3772,7 @@ dependencies = [ "bip39", "blake2-rfc", "bs58", - "chacha20", + "chacha20 0.9.1", "crossbeam-queue", "derive_more 2.1.1", "ed25519-zebra", @@ -2716,18 +3785,18 @@ dependencies = [ "hashbrown 0.16.1", "hex", "hmac 0.12.1", - "itertools", + "itertools 0.14.0", "libm", "libsecp256k1", "merlin", - "nom", + "nom 8.0.0", "num-bigint", "num-rational", "num-traits", "pbkdf2", "pin-project", "poly1305", - "rand", + "rand 0.8.6", "rand_chacha", "ruzstd", "schnorrkel", @@ -2735,7 +3804,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "sha3", - "siphasher", + "siphasher 1.0.3", "slab", "smallvec", "soketto", @@ -2759,7 +3828,7 @@ dependencies = [ "bip39", "blake2-rfc", "bs58", - "chacha20", + "chacha20 0.9.1", "crossbeam-queue", "derive_more 2.1.1", "ed25519-zebra", @@ -2772,18 +3841,18 @@ dependencies = [ "hashbrown 0.16.1", "hex", "hmac 0.12.1", - "itertools", + "itertools 0.14.0", "libm", "libsecp256k1", "merlin", - "nom", + "nom 8.0.0", "num-bigint", "num-rational", "num-traits", "pbkdf2", "pin-project", "poly1305", - "rand", + "rand 0.8.6", "rand_chacha", "ruzstd", "schnorrkel", @@ -2791,7 +3860,7 @@ dependencies = [ "serde_json", "sha2 0.10.9", "sha3", - "siphasher", + "siphasher 1.0.3", "slab", "smallvec", "soketto", @@ -2821,16 +3890,16 @@ dependencies = [ "futures-util", "hashbrown 0.16.1", "hex", - "itertools", + "itertools 0.14.0", "log", "lru", "parking_lot", "pin-project", - "rand", + "rand 0.8.6", "rand_chacha", "serde", "serde_json", - "siphasher", + "siphasher 1.0.3", "slab", "smol", "smoldot 2.0.0", @@ -2858,7 +3927,7 @@ dependencies = [ "futures", "httparse", "log", - "rand", + "rand 0.8.6", "sha1", ] @@ -2929,6 +3998,63 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "subxt" +version = "0.50.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440b28070d3bba98d637791bc7ebbe362f5beb9e749204c16caaf344fef260ba" +dependencies = [ + "async-trait", + "derive-where", + "either", + "frame-decode", + "frame-metadata", + "futures", + "hex", + "impl-serde", + "keccak-hash", + "parity-scale-codec", + "primitive-types", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-info", + "scale-info-legacy", + "scale-type-resolver", + "scale-value", + "serde", + "serde_json", + "sp-crypto-hashing", + "subxt-lightclient", + "subxt-macro", + "subxt-metadata", + "subxt-rpcs", + "subxt-utils-accountid32", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tracing", + "web-time", +] + +[[package]] +name = "subxt-codegen" +version = "0.50.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc8a165f929034fd00e9bfa86b63e5d7c26b635e526fa9cadb01389eab92029" +dependencies = [ + "getrandom 0.2.17", + "heck", + "parity-scale-codec", + "proc-macro2", + "quote", + "scale-info", + "scale-typegen", + "subxt-metadata", + "syn", + "thiserror 2.0.18", +] + [[package]] name = "subxt-lightclient" version = "0.50.1" @@ -2956,6 +4082,40 @@ dependencies = [ "web-time", ] +[[package]] +name = "subxt-macro" +version = "0.50.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5132bb78596d4957bf3039b9c54f5f88cefefd64ab61f0e71592526e14ef7f13" +dependencies = [ + "darling", + "parity-scale-codec", + "proc-macro-error2", + "quote", + "scale-typegen", + "subxt-codegen", + "subxt-metadata", + "subxt-utils-fetchmetadata", + "syn", +] + +[[package]] +name = "subxt-metadata" +version = "0.50.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e48c34696956f995df947adeb77061cb413377fb412487c41e7c2089112d5b" +dependencies = [ + "frame-decode", + "frame-metadata", + "hashbrown 0.14.5", + "parity-scale-codec", + "scale-info", + "scale-info-legacy", + "scale-type-resolver", + "sp-crypto-hashing", + "thiserror 2.0.18", +] + [[package]] name = "subxt-rpcs" version = "0.50.1" @@ -2976,11 +4136,39 @@ dependencies = [ "serde_json", "subxt-lightclient", "thiserror 2.0.18", + "tokio-util", "tracing", "url", "wasm-bindgen-futures", ] +[[package]] +name = "subxt-utils-accountid32" +version = "0.50.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d43f74707b4c7b7e1e40bf362aebaf42630211a8bcac46a94318284f305debd" +dependencies = [ + "base58", + "blake2", + "parity-scale-codec", + "scale-decode", + "scale-encode", + "scale-info", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "subxt-utils-fetchmetadata" +version = "0.50.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d58c4d891f3f8bd56acae29706b8bcde969ebb7421c447a8dff0117128416cb" +dependencies = [ + "hex", + "parity-scale-codec", + "thiserror 2.0.18", +] + [[package]] name = "syn" version = "2.0.117" @@ -2992,6 +4180,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.13.2" @@ -3022,6 +4219,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -3071,6 +4277,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.3" @@ -3102,9 +4317,11 @@ version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ + "bytes", "libc", "mio", "pin-project-lite", + "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.61.2", @@ -3140,6 +4357,35 @@ dependencies = [ "futures-core", "pin-project-lite", "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.21.0", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite 0.24.0", + "webpki-roots 0.26.11", ] [[package]] @@ -3156,6 +4402,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "1.1.1+spec-1.1.0" @@ -3174,7 +4429,7 @@ dependencies = [ "indexmap", "toml_datetime", "toml_parser", - "winnow", + "winnow 1.0.2", ] [[package]] @@ -3183,9 +4438,54 @@ version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow", + "winnow 1.0.2", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", ] +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.44" @@ -3215,6 +4515,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", ] [[package]] @@ -3223,9 +4535,16 @@ version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", "sharded-slab", + "smallvec", "thread_local", + "tracing", "tracing-core", + "tracing-log", ] [[package]] @@ -3253,6 +4572,38 @@ dependencies = [ "truapi", ] +[[package]] +name = "truapi-host-cli" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "bip39", + "blake2-rfc", + "clap", + "frame-metadata", + "futures", + "futures-util", + "hex", + "parity-scale-codec", + "reqwest", + "rustls", + "scale-info", + "serde", + "serde_json", + "sp-crypto-hashing", + "subxt-rpcs", + "tokio", + "tokio-stream", + "tokio-tungstenite 0.24.0", + "tracing", + "tracing-subscriber", + "truapi", + "truapi-platform", + "truapi-server", + "verifiable", +] + [[package]] name = "truapi-macros" version = "0.1.0" @@ -3273,6 +4624,7 @@ dependencies = [ "truapi", "unicode-normalization", "url", + "zeroize", ] [[package]] @@ -3282,12 +4634,12 @@ dependencies = [ "aes-gcm", "async-trait", "blake2-rfc", - "bs58", + "blake2b_simd", "console_error_panic_hook", "derive_more 2.1.1", + "frame-metadata", "futures", "futures-timer", - "futures-util", "getrandom 0.2.17", "hex", "hkdf", @@ -3295,8 +4647,8 @@ dependencies = [ "nanoid", "p256", "parity-scale-codec", - "pin-project", - "primitive-types", + "rand 0.8.6", + "scale-info", "schnorrkel", "send_wrapper 0.6.0", "serde", @@ -3304,14 +4656,19 @@ dependencies = [ "sha2 0.10.9", "sp-crypto-hashing", "substrate-bip39", + "subxt", "subxt-rpcs", "thiserror 1.0.69", + "tokio", + "tokio-tungstenite 0.21.0", "tracing", "tracing-subscriber", "truapi", "truapi-platform", "unicode-normalization", + "uniffi", "url", + "verifiable", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", @@ -3320,6 +4677,51 @@ dependencies = [ "zeroize", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.6", + "sha1", + "thiserror 1.0.69", + "url", + "utf-8", +] + +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.6", + "rustls", + "rustls-pki-types", + "sha1", + "thiserror 1.0.69", + "utf-8", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -3328,6 +4730,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", + "rand 0.8.6", "static_assertions", ] @@ -3382,6 +4785,134 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "uniffi" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3291800a6b06569f7d3e15bdb6dc235e0f0c8bd3eb07177f430057feb076415f" +dependencies = [ + "anyhow", + "camino", + "cargo_metadata", + "clap", + "uniffi_bindgen", + "uniffi_core", + "uniffi_macros", + "uniffi_pipeline", +] + +[[package]] +name = "uniffi-bindgen-cli" +version = "0.1.0" +dependencies = [ + "uniffi", +] + +[[package]] +name = "uniffi_bindgen" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a04b99fa7796eaaa7b87976a0dbdd1178dc1ee702ea00aca2642003aef9b669e" +dependencies = [ + "anyhow", + "askama", + "camino", + "cargo_metadata", + "fs-err", + "glob", + "goblin", + "heck", + "indexmap", + "once_cell", + "serde", + "tempfile", + "textwrap", + "toml", + "uniffi_internal_macros", + "uniffi_meta", + "uniffi_pipeline", + "uniffi_udl", +] + +[[package]] +name = "uniffi_core" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38a9a27529ccff732f8efddb831b65b1e07f7dea3fd4cacd4a35a8c4b253b98" +dependencies = [ + "anyhow", + "bytes", + "once_cell", + "static_assertions", +] + +[[package]] +name = "uniffi_internal_macros" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09acd2ce09c777dd65ee97c251d33c8a972afc04873f1e3b21eb3492ade16933" +dependencies = [ + "anyhow", + "indexmap", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "uniffi_macros" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5596f178c4f7aafa1a501c4e0b96236a96bc2ef92bdb453d83e609dad0040152" +dependencies = [ + "camino", + "fs-err", + "once_cell", + "proc-macro2", + "quote", + "serde", + "syn", + "toml", + "uniffi_meta", +] + +[[package]] +name = "uniffi_meta" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beadc1f460eb2e209263c49c4f5b19e9a02e00a3b2b393f78ad10d766346ecff" +dependencies = [ + "anyhow", + "siphasher 0.3.11", + "uniffi_internal_macros", + "uniffi_pipeline", +] + +[[package]] +name = "uniffi_pipeline" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd76b3ac8a2d964ca9fce7df21c755afb4c77b054a85ad7a029ad179cc5abb8a" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "tempfile", + "uniffi_internal_macros", +] + +[[package]] +name = "uniffi_udl" +version = "0.29.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319cf905911d70d5b97ce0f46f101619a22e9a189c8c46d797a9955e9233716" +dependencies = [ + "anyhow", + "textwrap", + "uniffi_meta", + "weedle2", +] + [[package]] name = "universal-hash" version = "0.5.1" @@ -3392,6 +4923,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" @@ -3410,6 +4947,12 @@ dependencies = [ "serde", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -3422,12 +4965,83 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "verifiable" +version = "0.5.0" +source = "git+https://github.com/paritytech/verifiable?rev=f65b39df04f2f9a453d78550438b189c96785285#f65b39df04f2f9a453d78550438b189c96785285" +dependencies = [ + "ark-scale", + "ark-serialize", + "ark-vrf", + "bounded-collections", + "parity-scale-codec", + "scale-info", + "sha2 0.10.9", + "smallvec", + "spin", +] + [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "w3f-pcs" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea1046a1deb6d26c34ba2d1f1bab4222d695d126502ee765f80b021753cb674" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "merlin", + "rayon", +] + +[[package]] +name = "w3f-plonk-common" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30408cda37b81bd7257319942584c794c5784d00d749757bc664656749a1472a" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "getrandom_or_panic", + "rand_core 0.6.4", + "rayon", + "w3f-pcs", +] + +[[package]] +name = "w3f-ring-proof" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cbfc4cb881a934e6f33c25927bf955d0cb18e52b94528bbc5fa28dddedb4cd1" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "ark-transcript", + "rayon", + "w3f-pcs", + "w3f-plonk-common", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -3438,6 +5052,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -3678,6 +5301,33 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.7", +] + +[[package]] +name = "webpki-roots" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "weedle2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "winapi-util" version = "0.1.11" @@ -3850,6 +5500,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "1.0.2" @@ -3975,11 +5634,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", - "rand_core", + "rand_core 0.6.4", "serde", "zeroize", ] +[[package]] +name = "yap" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe269e7b803a5e8e20cbd97860e136529cd83bf2c9c6d37b142467e7e1f051f" + [[package]] name = "yoke" version = "0.8.2" diff --git a/Makefile b/Makefile index b3e20965..6badef4e 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,9 @@ # Run `make help` for the list of targets. .DEFAULT_GOAL := help -.PHONY: help setup build codegen test check clean playground wasm wasm-crypto-test dev dev-bootstrap dev-link-check e2e-dotli matrix explorer +.PHONY: help setup build codegen test check clean playground wasm wasm-crypto-test uniffi dev dev-bootstrap dev-link-check e2e-dotli headless install matrix explorer +CARGO ?= cargo TRUAPI_PKG := js/packages/truapi PLAYGROUND := playground JS_PACKAGES := js/packages @@ -19,6 +20,8 @@ DOTLI_UI := $(DOTLI)/packages/ui DOTLI_HOST_WASM_LINK := $(DOTLI_UI)/node_modules/@parity/truapi-host SIGNER_BOT_BASE_URL ?= https://signing-bot-dev.novasama-tech.org/ SIGNER_BOT_NETWORK ?= paseo-next-v2 +SIGNER_BOT_BASE_URL_ORIGIN := $(origin SIGNER_BOT_BASE_URL) +SIGNER_BOT_NETWORK_ORIGIN := $(origin SIGNER_BOT_NETWORK) VITE_NETWORKS ?= paseo-next-v2,previewnet export SIGNER_BOT_BASE_URL export SIGNER_BOT_NETWORK @@ -29,6 +32,8 @@ export VITE_NETWORKS # preview by default. Override with `DOTLI_PREVIEW=preview` to test production # preview behavior. DOTLI_PREVIEW ?= preview:debug +TRUAPI_WASM_PROFILE ?= dev +E2E_DOTLI_WASM_PROFILE ?= release help: ## Show this help. @awk 'BEGIN { FS = ":.*##"; printf "Usage: make \n\nTargets:\n" } \ @@ -48,6 +53,13 @@ build: ## Build the Rust workspace and the TypeScript client. cd $(TRUAPI_PKG) && npm run build cd $(HOST_WASM_PKG) && npm run build +headless: ## Build everything the headless-host e2e needs; then run rust/crates/truapi-host-cli/e2e/run.sh. + cargo build -p truapi-host-cli + cd $(TRUAPI_PKG) && npm run build + +install: headless ## Install the truapi-host CLI into Cargo's bin dir; use as `make headless install`. + cargo install --path rust/crates/truapi-host-cli --bin truapi-host --locked --force + codegen: ## Regenerate generated TS/Rust artifacts from the Rust crates. ./scripts/codegen.sh cd $(PLAYGROUND) && rm -rf node_modules/@parity && yarn install @@ -58,6 +70,32 @@ wasm: ## Rebuild the truapi-server WASM artifacts under js/packages/truapi-host/ wasm-crypto-test: ## Run crypto/vector tests on wasm32 via wasm-pack/node. wasm-pack test --node rust/crates/truapi-server --test wasm_crypto_vectors --no-default-features +UNIFFI_CDYLIB_DIR := target/release +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Darwin) +UNIFFI_CDYLIB := $(UNIFFI_CDYLIB_DIR)/libtruapi_server.dylib +else +UNIFFI_CDYLIB := $(UNIFFI_CDYLIB_DIR)/libtruapi_server.so +endif + +UNIFFI_SWIFT_TMP := target/uniffi-swift-out + +uniffi: ## Regenerate Swift bindings from truapi-server cdylib. + $(CARGO) build -p truapi-server --release --features ws-bridge + rm -rf $(UNIFFI_SWIFT_TMP) + mkdir -p $(UNIFFI_SWIFT_TMP) + $(CARGO) run -p uniffi-bindgen-cli -- generate \ + --library $(UNIFFI_CDYLIB) \ + --language swift \ + --out-dir $(UNIFFI_SWIFT_TMP) + mkdir -p ios/truapi-host/Sources/truapi_serverFFI/include + cp $(UNIFFI_SWIFT_TMP)/truapi_server.swift \ + ios/truapi-host/Sources/TrUAPIHost/truapi_server.swift + cp $(UNIFFI_SWIFT_TMP)/truapi_serverFFI.h \ + ios/truapi-host/Sources/truapi_serverFFI/include/truapi_serverFFI.h + cp $(UNIFFI_SWIFT_TMP)/truapi_serverFFI.modulemap \ + ios/truapi-host/Sources/truapi_serverFFI/include/module.modulemap + test: ## Run Rust + TypeScript client tests. cargo test --workspace cd $(TRUAPI_PKG) && npm test @@ -101,8 +139,9 @@ dev-bootstrap: ## Prepare ignored generated/build artifacts needed by dotli prev # that only exist after codegen.sh, which also builds the packages. if [ ! -d node_modules ]; then npm ci --ignore-scripts; fi if [ ! -f "$(HOST_CALLBACKS_GENERATED)" ] || [ ! -f "$(HOST_WASM_ADAPTER_GENERATED)" ] || [ ! -f "$(HOST_WASM_WORKER_CALLBACKS_GENERATED)" ]; then ./scripts/codegen.sh; fi + cd $(TRUAPI_PKG) && npm run build cd $(HOST_WASM_PKG) && npm run build - TRUAPI_WASM_PROFILE=dev $(MAKE) wasm + TRUAPI_WASM_PROFILE=$(TRUAPI_WASM_PROFILE) $(MAKE) wasm cd $(PLAYGROUND) && yarn install --frozen-lockfile cd $(DOTLI) && bun install --frozen-lockfile $(MAKE) dev-link-check @@ -127,14 +166,16 @@ e2e-dotli: ## Fully automated dotli + playground diagnosis e2e. Requires SIGNER_ @SIGNER_BOT_SVC_TOKEN_ENV="$$SIGNER_BOT_SVC_TOKEN"; \ SIGNER_BOT_BASE_URL_ENV="$$SIGNER_BOT_BASE_URL"; \ SIGNER_BOT_NETWORK_ENV="$$SIGNER_BOT_NETWORK"; \ + SIGNER_BOT_BASE_URL_ORIGIN="$(SIGNER_BOT_BASE_URL_ORIGIN)"; \ + SIGNER_BOT_NETWORK_ORIGIN="$(SIGNER_BOT_NETWORK_ORIGIN)"; \ set -a; \ if [ -f .env ]; then . ./.env; fi; \ set +a; \ if [ -n "$$SIGNER_BOT_SVC_TOKEN_ENV" ]; then SIGNER_BOT_SVC_TOKEN="$$SIGNER_BOT_SVC_TOKEN_ENV"; export SIGNER_BOT_SVC_TOKEN; fi; \ - if [ -n "$$SIGNER_BOT_BASE_URL_ENV" ]; then SIGNER_BOT_BASE_URL="$$SIGNER_BOT_BASE_URL_ENV"; export SIGNER_BOT_BASE_URL; fi; \ - if [ -n "$$SIGNER_BOT_NETWORK_ENV" ]; then SIGNER_BOT_NETWORK="$$SIGNER_BOT_NETWORK_ENV"; export SIGNER_BOT_NETWORK; fi; \ - if [ "$$E2E_DOTLI_SMOKE" != "1" ]; then test -n "$$SIGNER_BOT_SVC_TOKEN" || (echo "Missing SIGNER_BOT_SVC_TOKEN. e2e-dotli requires signer-bot; without it a human phone scan is required."; exit 1); fi; \ - $(MAKE) dev-bootstrap; \ + if [ "$$SIGNER_BOT_BASE_URL_ORIGIN" != "file" ] && [ -n "$$SIGNER_BOT_BASE_URL_ENV" ]; then SIGNER_BOT_BASE_URL="$$SIGNER_BOT_BASE_URL_ENV"; export SIGNER_BOT_BASE_URL; fi; \ + if [ "$$SIGNER_BOT_NETWORK_ORIGIN" != "file" ] && [ -n "$$SIGNER_BOT_NETWORK_ENV" ]; then SIGNER_BOT_NETWORK="$$SIGNER_BOT_NETWORK_ENV"; export SIGNER_BOT_NETWORK; fi; \ + if [ "$$E2E_DOTLI_SMOKE" != "1" ]; then test -n "$$SIGNER_BOT_SVC_TOKEN" || { echo "Missing SIGNER_BOT_SVC_TOKEN. e2e-dotli requires signer-bot; without it a human phone scan is required."; exit 1; }; fi; \ + TRUAPI_WASM_PROFILE=$(E2E_DOTLI_WASM_PROFILE) $(MAKE) dev-bootstrap; \ cd $(PLAYGROUND) && bun tests/e2e/dotli-diagnosis.ts matrix: ## Regenerate the host compatibility matrix from explorer/diagnosis-reports. diff --git a/README.md b/README.md index a5c38f00..78a44a51 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ rust/crates/ truapi-macros/ #[wire(id = N)] proc-macro truapi-platform/ Host syscall traits used by truapi-server (storage, navigation, consent, ...) truapi-server/ Rust runtime that hosts implement: dispatcher, frames, SCALE, WASM surface + truapi-host-cli/ Headless pairing-host + signing-host CLIs that pair over the real People-chain statement store for local e2e (signing-bot replacement) js/packages/ truapi/ @parity/truapi TypeScript client truapi-host/ @parity/truapi-host: WASM-backed host runtime; entries `.` diff --git a/deny.toml b/deny.toml index 9305a03f..500c13c3 100644 --- a/deny.toml +++ b/deny.toml @@ -9,6 +9,8 @@ allow = [ "BSD-2-Clause", "BSD-3-Clause", "CC0-1.0", + "CDLA-Permissive-2.0", + "ISC", "Unicode-3.0", "Unlicense", "Zlib", @@ -18,6 +20,10 @@ confidence-threshold = 0.8 # uniffi is MPL-2.0: file-level weak copyleft, consumed unmodified as a # dependency, which MPL-2.0 permits without affecting the MIT outbound licence. # Scoped per crate so MPL-2.0 stays disallowed everywhere else. +# +# verifiable is GPL-3.0-or-later with the Classpath exception, consumed as an +# unmodified library dependency for ring-VRF proof construction. Keep the +# exception scoped to that crate. exceptions = [ { name = "uniffi", allow = ["MPL-2.0"] }, { name = "uniffi_bindgen", allow = ["MPL-2.0"] }, @@ -27,4 +33,5 @@ exceptions = [ { name = "uniffi_meta", allow = ["MPL-2.0"] }, { name = "uniffi_pipeline", allow = ["MPL-2.0"] }, { name = "uniffi_udl", allow = ["MPL-2.0"] }, + { name = "verifiable", allow = ["GPL-3.0-or-later WITH Classpath-exception-2.0"] }, ] diff --git a/docs/issue-drafts/bulletin-preimage-in-core.md b/docs/issue-drafts/bulletin-preimage-in-core.md new file mode 100644 index 00000000..0f841b26 --- /dev/null +++ b/docs/issue-drafts/bulletin-preimage-in-core.md @@ -0,0 +1,336 @@ +# Move Bulletin preimage submission into the Rust core + +## TL;DR + +Preimage submission to the Bulletin chain now happens **entirely inside the Rust +core** (`truapi-server`). The core builds, signs, and submits the +`TransactionStorage.store` extrinsic itself, routing the chain traffic through +the host's existing `chain.connect` byte-pipe — the same transport products +already use for any chain access. + +Previously the core handed the host a _signing capability_ and the host built +and submitted the transaction with PAPI. That seam is gone. As a result: + +- The wallet-delegated **allowance secret never leaves the core** (it no longer + crosses the host / FFI boundary as a signer handle). +- The host's only remaining preimage job is **content lookup** (Helia / IPFS). +- All hosts (web, and later mobile over uniffi) get identical submission + behaviour for free, because the logic lives in the shared core rather than in + each host's JS/native code. + +This issue explains the moving parts and, most importantly, **the messages +exchanged** between the product, the Rust core, the host, and the network. + +--- + +## Why + +The base branch already routes every chain call through one host callback, +`chain.connect(genesisHash)`, which returns a JSON-RPC byte pipe. Preimage +submission was the one chain write that did _not_ use it: instead the core +derived an allowance signer and passed a `sign(payload)` closure out to the +host, which reconstructed a PAPI transaction and submitted it. That meant: + +- Every host reimplemented extrinsic construction/submission (and dotli pulled + `@novasamatech` + PAPI signer deps back in to do it). +- The allowance secret's signing capability crossed the worker / FFI boundary. +- Submission behaviour (nonce, mortality, dispatch-error handling, retries) + diverged per host. + +Folding it into the core removes all three. + +--- + +## Before vs after: who owns what + +The topology is unchanged — the core still reaches the network only through the +host — what changes is **ownership**. Each box below lists what that side owns; +every arrow crossing the vertical boundary is labelled with exactly what +crosses it. + +Before, the *secret bytes* were core-owned, but the *capability to use them* — +and everything that decides what gets signed — was host-owned: + +``` +BEFORE + core-owned (WASM worker) host-owned (JS main thread) + +------------------------------+ || +------------------------------+ + | Rust core | || | dotli (PAPI) | + | | || | | + | owns: | || | owns: | + | - allowance secret (64 B) | || | - signer handle | + | - sign() execution | || | { publicKey, sign() } | + | | || | - tx builder (PAPI) | + | | || | - decides WHAT is signed | + | | || | - submission + watch | + +------------------------------+ || +------------------------------+ + + crosses ||: core --[ signer handle ]--> host (a live signing capability) + core <--[ sign(payload) ]-- host (one request per tx) + core --[ signature ]--> host --> Bulletin +``` + +After, everything signing-related sits on the core side; the only thing that +crosses the boundary during submission is opaque JSON-RPC text: + +``` +AFTER + core-owned (WASM worker) host-owned (JS main thread) + +------------------------------+ || +------------------------------+ + | Rust core | || | dotli | + | | || | | + | owns: | || | owns: | + | - allowance secret (64 B) | || | - permission/confirm modals | + | - signer (crate-private, | || | - chain.connect byte pipe | + | never exported) | || | (forwards verbatim) | + | - tx builder (subxt) | || | - lookupPreimage backend | + | - decides WHAT is signed | || | (Helia / IPFS) | + | - submission + watch | || | | + +------------------------------+ || +------------------------------+ + + crosses ||: core --[ JSON-RPC request ]--> host --> Bulletin + core <--[ JSON-RPC response ]-- host + opaque strings only: no key, no capability, no sign requests +``` + +The security consequence: before, host code held a live capability and chose +the payloads it signed; a compromised host could sign arbitrary Bulletin +transactions with the user's allowance. After, the host can at worst drop or +corrupt bytes — a lie in either direction produces a transaction the real +chain rejects, never a signature over attacker-chosen content. + +--- + +## Actors and responsibilities + +| Actor | Runs where | Owns | +| -------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------ | +| **Product** | sandboxed iframe / app | speaks TrUAPI; never sees chains or keys | +| **Rust core** (`truapi-server`) | WASM in a Web Worker (web); native lib (mobile) | wire protocol, tx build + sign, submit + watch, allowance key | +| **Host** (dotli / mobile shell) | main thread / OS shell | user modals, `chain.connect` transport, `lookupPreimage` content backend | +| **Wallet** (paired signing host) | phone | allocates the Bulletin allowance key over SSO | +| **Network** | — | Bulletin chain (writes) + People chain (allowance allocation / SSO) | + +--- + +## Message flow: preimage submission (happy path) + +This is the core of the change. The product calls one wire method, +`preimage.submit(value)`; everything below it is new in-core work. + +The columns are ownership lanes. A boundary glyph shows what crosses it on that +row: `>` left-to-right, `<` right-to-left, `:` nothing. Everything in the CORE +lane stays in the WASM worker unless a glyph carries it out. + +``` + PRODUCT | CORE (holds keys, builds+signs) : HOST (modals+pipe) : NET + ---------+------------------------------------+--------------------+--- + submit > receive : : + | -- gate (unchanged) -- : : + | remotePermission > prompt user : + | confirmUserAction > prompt user : + | -- allowance key (cached) -- : : + | requestResourceAllocation > relay SSO > wlt + | slotAccountKey < passthrough < key + | [[ 64-B secret stays in core ]] : : + | -- build + submit via pipe -- : : + | chain.connect(bulletin) > open pipe : + | chainHead_v1_follow > forward > N + | Metadata_metadata_at_version > forward > N + | AccountNonceApi_account_nonce > forward > N + | [[ build + SIGN store(value) ]] : : + | validate_transaction (dry-run) > forward > N + | transaction_v1_broadcast > forward > N + | chainHead_v1_body (watch) > forward > N + | chainHead_v1_storage(Events) > forward > N + key< return blake2_256(value) : : + | [[ prime lookup cache ]] : : + + boundary glyphs: > message crosses left->right < crosses right->left + : boundary, no message on this row + CORE:HOST is the WASM-worker edge; [[..]] work never leaves the core; NET is + the Bulletin chain, reached only through the host's pipe (wlt = paired wallet) +``` + +Key points on this flow: + +- The **gate** (permission + confirmation) is unchanged from the base protocol; + it still guards the write. +- The **dry-run** is load-bearing: `transaction_v1_broadcast` is + spec-guaranteed to be _silent_ on invalid transactions, so without a + `validate_transaction` call the core could never distinguish "rejected" from + "still pending" and would only ever see a timeout. +- Inclusion is confirmed by **matching the extrinsic hash in a block body**, + then the **dispatch outcome** is read from `System.Events` — matching the + fidelity the old PAPI `signSubmitAndWatch` path had. + +--- + +## Message flow: allowance key (the one secret) + +The allowance key is a wallet-delegated, scoped signing capability. The wallet +owns *minting* it; the core owns *holding and using* it; the host only relays +the SSO messages and never sees the resulting secret used. It is allocated once +per (session, product), cached in the core, and used only to sign the `store` +call. + +``` + CORE (holds + uses the key) : HOST (relays SSO) : WALLET (mints) + ---------------------------------------+--------------------+--- + -- first submit for this product -- : : + requestResourceAllocation > relay (Ignore) > allocate + slotAccountKey < passthrough < { key } + [[ store in memory + persisted ]] : : + [[ used only to sign store() calls ]] : : + : : + -- later: allowance is exhausted -- : : + [[ evict the cached key ]] : : + requestResourceAllocation > relay (Increase) > mint fresh, + slotAccountKey < passthrough < larger one + [[ retry the submit exactly once ]] : : + + > crosses core -> host -> wallet < the reply crossing back + the key lands in CORE and is used there; the host never sees it signing +``` + +The retry is bounded: the core refreshes the allowance and retries **at most +once**, and only when the failure is a typed "allowance rejected" signal (from +the dry-run or from a `TransactionStorage` authorization error in the events) — +never on transport errors or nonce races. + +--- + +## Message flow: lookup (unchanged owner, new integrity check) + +The *content backend* is host-owned (the host chooses Helia P2P or an IPFS +gateway); the *cache* and the *integrity gate* are core-owned. So even though +the bytes originate on the host side, the core decides whether they reach the +product. + +``` + CORE (cache + integrity gate) : HOST (content backend) + -----------------------------------------+----------------------- + lookup_subscribe(key) from product : + : + cache hit (primed by in-core submit): : + emit value once, keep open : + : + cache miss: : + lookupPreimage(key) > poll Helia / IPFS + value | miss < host-owned bytes + [[ gate: blake2_256(value)==key? ]] : + match: forward mismatch: -> miss : + + > request crosses into the host < host's bytes cross back + the backend is host-owned; the cache + integrity gate are core-owned, + so the core decides what reaches the product (a mismatch is warn-logged) +``` + +A host that returns bytes not matching the requested key can no longer feed a +product forged content: the core's integrity gate downgrades the mismatch to a +miss before it reaches the product. + +--- + +## Failure handling and the inclusion watch + +The submit flow returns a typed error that maps to a stable reason string on the +wire (`PreimageSubmitError::Unknown { reason }` — the product wire is +unchanged). The decision the core makes at each failure: + +``` + dry-run: validate_transaction + | + +-- Valid ................................. broadcast + watch (see below) + +-- Invalid::Payment / Custom / BadSigner . allowance rejected -> refresh + retry once + +-- Invalid::Future / Stale ............... nonce race (no retry) + +-- other Invalid ......................... invalid (no retry) + + broadcast + watch: included? + | + +-- ExtrinsicSuccess ...................... return the preimage key + +-- TransactionStorage auth error ......... allowance rejected -> refresh + retry once + +-- other dispatch error .................. dispatch failed + +-- 120s elapsed / follow stopped ......... broadcast, inclusion unverified +``` + +"Allowance rejected" is the only outcome that refreshes the key +(`onExisting=Increase`) and retries — at most once, in both the dry-run and the +dispatch branches. + +The inclusion watch is a single event loop over one ephemeral chainHead follow. +It fetches a block body only after the allowance account's nonce is seen to +advance (so it does not download every block), matches by extrinsic hash, and +releases pins as it goes. Because the follow is dropped when the 120 s budget or +a cancellation fires, its pins and connection lease are released automatically. + +--- + +## Security invariants + +Because the chain provider is an untrusted byte pipe (especially in RPC-gateway +mode), the core enforces four invariants so a hostile or buggy provider cannot +subvert the allowance key: + +1. **Genesis is config-pinned.** The signed payload's genesis hash always comes + from host _configuration_, never from provider-echoed chain data — so a + provider cannot redirect the allowance-key signature to a different chain. + Every other provider-supplied input (spec/tx version, nonce, mortality + anchor, metadata) is then fail-closed: lying about it yields a signature the + real chain rejects, never one valid elsewhere. +2. **Call is pinned.** Name resolution of `TransactionStorage.store` is + hard-asserted against audited pallet/call indices, and the metadata-built + call bytes are checked byte-for-byte against a canonically built copy — so + provider metadata cannot make the key sign a different call. +3. **Signer is confined.** The only allowance-key -> signer conversion is + crate-private to the bulletin module; the signer is transient, never stored, + never logged, and the key type is zeroized on drop. +4. **Lookup is content-addressed.** Host-returned bytes are verified against the + requested key before reaching the product. + +A crafted `NewBlock` parent link (self-referential or cyclic) is also guarded in +the inclusion watch so the provider cannot spin the worker. + +--- + +## What changed (high-level map) + +- `truapi-server/src/host_logic/extrinsic.rs` — offline subxt assembler: + config-pinned `SubstrateConfig`, sr25519 signer, metadata / validity / events + / header decoders. +- `truapi-server/src/host_logic/bulletin.rs` — `store{data}` build + sign, call + pinning, byte-level call-data encoder. +- `truapi-server/src/runtime/bulletin_rpc.rs` — the submit flow (follow -> + metadata -> nonce -> dry-run -> broadcast -> watch -> events) and its typed + errors. +- `truapi-server/src/runtime.rs` — `Preimage::submit` ordering + refresh/retry; + `lookup_subscribe` cache + integrity check. +- `truapi-platform` — `PreimageHost` keeps only `lookupPreimage`; + `BulletinAllowanceKey` is zeroized on drop; configs gain an optional Bulletin + genesis hash. +- Host TS (`@parity/truapi-host`) + dotli — the signer bridge is removed; dotli + keeps only lookup, threads the Bulletin genesis into its runtime config, and + routes the Bulletin genesis through `chain.connect` on both backends. + +The **product-facing wire is unchanged** — `preimage.submit` / +`preimage.lookup_subscribe` keep their wire ids and shapes, so products need no +changes. + +--- + +## Verification + +- Rust: build / fmt / clippy (`-D warnings`) / tests all green; wasm32 compiles; + `cargo deny` licenses ok. New unit tests cover extrinsic construction against + real Bulletin metadata, genesis-binding, call pinning, the extension-encoding + rules, and the inclusion-watch cycle guard. +- Host TS: `tsc` + `bun` tests green. WASM bundle grows ~0.5 MB (subxt offline). +- **Manual / e2e gates** (network + signer-bot, not in CI): the live-chain + dry-run encoding proof and `make e2e-dotli` preimage flow. + +## Follow-ups + +- Signing-host (mobile local-key) role: derive the Bulletin allowance key from + root entropy so submission works there too — everything downstream of the + allowance-key fetch is already shared. +- Reuse `host_logic/extrinsic.rs` for the local `create_transaction` path. diff --git a/explorer/diagnosis-reports/headless-pairing.md b/explorer/diagnosis-reports/headless-pairing.md new file mode 100644 index 00000000..fb77bf8f --- /dev/null +++ b/explorer/diagnosis-reports/headless-pairing.md @@ -0,0 +1,68 @@ +## Truapi Headless Pairing Host Diagnosis + +| Method | Status | Details | +| --- | --- | --- | +| `Account/connection_status_subscribe` | ✅ | | +| `Account/get_account` | ✅ | | +| `Account/get_account_alias` | ✅ | | +| `Account/create_account_proof` | ⏭️ | | +| `Account/get_legacy_accounts` | ✅ | | +| `Account/get_user_id` | ✅ | | +| `Account/request_login` | ✅ | | +| `Chain/follow_head_subscribe` | ✅ | | +| `Chain/get_head_header` | ✅ | | +| `Chain/get_head_body` | ✅ | | +| `Chain/get_head_storage` | ✅ | | +| `Chain/call_head` | ✅ | | +| `Chain/unpin_head` | ✅ | | +| `Chain/continue_head` | ✅ | | +| `Chain/stop_head_operation` | ✅ | | +| `Chain/get_spec_genesis_hash` | ✅ | | +| `Chain/get_spec_chain_name` | ✅ | | +| `Chain/get_spec_properties` | ✅ | | +| `Chain/broadcast_transaction` | ✅ | | +| `Chain/stop_transaction` | ✅ | | +| `Chat/create_room` | ⏭️ | | +| `Chat/register_bot` | ⏭️ | | +| `Chat/list_subscribe` | ⏭️ | | +| `Chat/post_message` | ⏭️ | | +| `Chat/action_subscribe` | ⏭️ | | +| `Chat/custom_message_render_subscribe` | ⏭️ | | +| `Coin Payment/create_purse` | ⏭️ | | +| `Coin Payment/query_purse` | ⏭️ | | +| `Coin Payment/rebalance_purse` | ⏭️ | | +| `Coin Payment/delete_purse` | ⏭️ | | +| `Coin Payment/create_receivable` | ⏭️ | | +| `Coin Payment/create_cheque` | ⏭️ | | +| `Coin Payment/deposit` | ⏭️ | | +| `Coin Payment/refund` | ⏭️ | | +| `Coin Payment/listen_for_payment` | ⏭️ | | +| `Entropy/derive` | ✅ | | +| `Local Storage/read` | ✅ | | +| `Local Storage/write` | ✅ | | +| `Local Storage/clear` | ✅ | | +| `Notifications/send_push_notification` | ✅ | | +| `Notifications/cancel_push_notification` | ✅ | | +| `Payment/balance_subscribe` | ⏭️ | | +| `Payment/top_up` | ⏭️ | | +| `Payment/request` | ⏭️ | | +| `Payment/status_subscribe` | ⏭️ | | +| `Permissions/request_device_permission` | ✅ | | +| `Permissions/request_remote_permission` | ✅ | | +| `Preimage/lookup_subscribe` | ✅ | | +| `Preimage/submit` | ✅ | | +| `Resource Allocation/request` | ✅ | | +| `Signing/create_transaction` | ✅ | | +| `Signing/create_transaction_with_legacy_account` | ✅ | | +| `Signing/sign_raw_with_legacy_account` | ✅ | | +| `Signing/sign_payload_with_legacy_account` | ✅ | | +| `Signing/sign_raw` | ✅ | | +| `Signing/sign_payload` | ✅ | | +| `Statement Store/subscribe` | ✅ | | +| `Statement Store/create_proof` | ✅ | | +| `Statement Store/submit` | ✅ | | +| `Statement Store/create_proof_authorized` | ✅ | | +| `System/handshake` | ✅ | | +| `System/feature_supported` | ✅ | | +| `System/navigate_to` | ✅ | | +| `Theme/subscribe` | ✅ | | diff --git a/explorer/diagnosis-reports/headless-signing.md b/explorer/diagnosis-reports/headless-signing.md new file mode 100644 index 00000000..36667911 --- /dev/null +++ b/explorer/diagnosis-reports/headless-signing.md @@ -0,0 +1,68 @@ +## Truapi Headless Signing Host Diagnosis + +| Method | Status | Details | +| --- | --- | --- | +| `Account/connection_status_subscribe` | ✅ | | +| `Account/get_account` | ✅ | | +| `Account/get_account_alias` | ✅ | | +| `Account/create_account_proof` | ⏭️ | | +| `Account/get_legacy_accounts` | ✅ | | +| `Account/get_user_id` | ✅ | | +| `Account/request_login` | ✅ | | +| `Chain/follow_head_subscribe` | ✅ | | +| `Chain/get_head_header` | ✅ | | +| `Chain/get_head_body` | ✅ | | +| `Chain/get_head_storage` | ✅ | | +| `Chain/call_head` | ✅ | | +| `Chain/unpin_head` | ✅ | | +| `Chain/continue_head` | ✅ | | +| `Chain/stop_head_operation` | ✅ | | +| `Chain/get_spec_genesis_hash` | ✅ | | +| `Chain/get_spec_chain_name` | ✅ | | +| `Chain/get_spec_properties` | ✅ | | +| `Chain/broadcast_transaction` | ✅ | | +| `Chain/stop_transaction` | ✅ | | +| `Chat/create_room` | ⏭️ | | +| `Chat/register_bot` | ⏭️ | | +| `Chat/list_subscribe` | ⏭️ | | +| `Chat/post_message` | ⏭️ | | +| `Chat/action_subscribe` | ⏭️ | | +| `Chat/custom_message_render_subscribe` | ⏭️ | | +| `Coin Payment/create_purse` | ⏭️ | | +| `Coin Payment/query_purse` | ⏭️ | | +| `Coin Payment/rebalance_purse` | ⏭️ | | +| `Coin Payment/delete_purse` | ⏭️ | | +| `Coin Payment/create_receivable` | ⏭️ | | +| `Coin Payment/create_cheque` | ⏭️ | | +| `Coin Payment/deposit` | ⏭️ | | +| `Coin Payment/refund` | ⏭️ | | +| `Coin Payment/listen_for_payment` | ⏭️ | | +| `Entropy/derive` | ✅ | | +| `Local Storage/read` | ✅ | | +| `Local Storage/write` | ✅ | | +| `Local Storage/clear` | ✅ | | +| `Notifications/send_push_notification` | ✅ | | +| `Notifications/cancel_push_notification` | ✅ | | +| `Payment/balance_subscribe` | ⏭️ | | +| `Payment/top_up` | ⏭️ | | +| `Payment/request` | ⏭️ | | +| `Payment/status_subscribe` | ⏭️ | | +| `Permissions/request_device_permission` | ✅ | | +| `Permissions/request_remote_permission` | ✅ | | +| `Preimage/lookup_subscribe` | ✅ | | +| `Preimage/submit` | ✅ | | +| `Resource Allocation/request` | ✅ | | +| `Signing/create_transaction` | ✅ | | +| `Signing/create_transaction_with_legacy_account` | ✅ | | +| `Signing/sign_raw_with_legacy_account` | ✅ | | +| `Signing/sign_payload_with_legacy_account` | ✅ | | +| `Signing/sign_raw` | ✅ | | +| `Signing/sign_payload` | ✅ | | +| `Statement Store/subscribe` | ✅ | | +| `Statement Store/create_proof` | ✅ | | +| `Statement Store/submit` | ✅ | | +| `Statement Store/create_proof_authorized` | ✅ | | +| `System/handshake` | ✅ | | +| `System/feature_supported` | ✅ | | +| `System/navigate_to` | ✅ | | +| `Theme/subscribe` | ✅ | | diff --git a/explorer/diagnosis-reports/headless.md b/explorer/diagnosis-reports/headless.md new file mode 100644 index 00000000..d3c5564d --- /dev/null +++ b/explorer/diagnosis-reports/headless.md @@ -0,0 +1,68 @@ +## Truapi Headless Pairing Host Diagnosis + +| Method | Status | Details | +| --- | --- | --- | +| `Account/connection_status_subscribe` | ✅ | connection status: Connected | +| `Account/get_account` | ✅ | account retrieved: { "account": { "publicKey": "0xf41df7581a7a4bdf59ab2497f3d86dd8ea14db35c5c1930790d5a3554d0bef13" } } other product account retrieved after approval: { "account": { "publicKey": "0x54931f317cc49b2448a7fd1c1bc816b038065eac9c19a8c53fe6cff21419560d" } } | +| `Account/get_account_alias` | ✅ | account alias: { "context": "0x05cc3451e5a525ff21f0a62ffe5e5c184fa4cd790bbaead4ef44ab8dc914ecee", "alias": "0x34cc10180a6fc6977f179b03ae39a261ae5cd44fab26d2086545e00b1b94368c" } | +| `Account/create_account_proof` | ⏭️ | | +| `Account/get_legacy_accounts` | ✅ | legacy accounts: { "accounts": [ { "publicKey": "0xf41df7581a7a4bdf59ab2497f3d86dd8ea14db35c5c1930790d5a3554d0bef13", "name": "pgherveou.06" } ] } | +| `Account/get_user_id` | ✅ | user id: { "primaryUsername": "pgherveouu" } | +| `Account/request_login` | ✅ | login completed: AlreadyConnected | +| `Chain/follow_head_subscribe` | ✅ | head follow event: { "tag": "Initialized", "value": { "finalizedBlockHashes": [ "0x24a8038e7cc8a27d6fec2ae9b77b16785a1d1c794c6a365fac0741c352262364", "0x46c922275f522cf267838ffefde7b9a06390e798c306cb84c866e5bde6d55c4c", "0xdc7034d48de1f314b6bff28cd8c20600f45426188720d99bba5a058a63a2cb03", "0x43c1... | +| `Chain/get_head_header` | ✅ | block header: { "header": "0xd7a5dcde73a638f6cf32ddf9742e8ed344f3d74a60238baee743f2afdd6a138d22506200d0ed8a003223ddb768e65599cb3c356a59f42b2cf9c705dab8fff471b7fe013837993da375488a851df8efd0f70c3ea683246f565d680046a0feddecb481c37c1006434d4c53100101010c0661757261202930dc0800000000045250535290018a90... | +| `Chain/get_head_body` | ✅ | block body: { "operation": { "tag": "Started", "value": { "operationId": "0" } } } | +| `Chain/get_head_storage` | ✅ | storage value: { "operation": { "tag": "Started", "value": { "operationId": "0" } } } | +| `Chain/call_head` | ✅ | runtime call result: { "operation": { "tag": "Started", "value": { "operationId": "0" } } } | +| `Chain/unpin_head` | ✅ | blocks unpinned | +| `Chain/continue_head` | ✅ | operation continued | +| `Chain/stop_head_operation` | ✅ | operation stopped | +| `Chain/get_spec_genesis_hash` | ✅ | genesis hash: { "genesisHash": "0xbf0488dbe9daa1de1c08c5f743e26fdc2a4ecd74cf87dd1b4b1eeb99ae4ef19f" } | +| `Chain/get_spec_chain_name` | ✅ | chain name: { "chainName": "Paseo Asset Hub Next" } | +| `Chain/get_spec_properties` | ✅ | chain properties: { "properties": "{\"tokenDecimals\":10,\"tokenSymbol\":\"PAS\"}" } | +| `Chain/broadcast_transaction` | ✅ | transaction broadcast: { "operationId": "kVxLWAWJZIuYd3KM" } | +| `Chain/stop_transaction` | ❌ | stopTransaction failed: { "error": { "tag": "HostFailure", "value": { "reason": "remote_chain_transaction_stop: User error: Invalid operation id (-32602)" } } } | +| `Chat/create_room` | ⏭️ | | +| `Chat/register_bot` | ⏭️ | | +| `Chat/list_subscribe` | ⏭️ | | +| `Chat/post_message` | ⏭️ | | +| `Chat/action_subscribe` | ⏭️ | | +| `Chat/custom_message_render_subscribe` | ⏭️ | | +| `Coin Payment/create_purse` | ⏭️ | | +| `Coin Payment/query_purse` | ⏭️ | | +| `Coin Payment/rebalance_purse` | ⏭️ | | +| `Coin Payment/delete_purse` | ⏭️ | | +| `Coin Payment/create_receivable` | ⏭️ | | +| `Coin Payment/create_cheque` | ⏭️ | | +| `Coin Payment/deposit` | ⏭️ | | +| `Coin Payment/refund` | ⏭️ | | +| `Coin Payment/listen_for_payment` | ⏭️ | | +| `Entropy/derive` | ✅ | entropy derived: { "entropy": "0x9ad6f1f6ac64687863a3456a7ddcb06a94c0b9a950930bb8eea3b51743f70baa" } | +| `Local Storage/read` | ✅ | storage value read: | +| `Local Storage/write` | ✅ | storage write succeeded | +| `Local Storage/clear` | ✅ | storage clear succeeded | +| `Notifications/send_push_notification` | ✅ | notification sent: { "id": 1 } | +| `Notifications/cancel_push_notification` | ✅ | notification cancelled | +| `Payment/balance_subscribe` | ⏭️ | | +| `Payment/top_up` | ⏭️ | | +| `Payment/request` | ⏭️ | | +| `Payment/status_subscribe` | ⏭️ | | +| `Permissions/request_device_permission` | ✅ | device permission result: { "granted": true } | +| `Permissions/request_remote_permission` | ✅ | remote permission result: { "granted": true } | +| `Preimage/lookup_subscribe` | ❌ | submit failed: { "error": { "tag": "Domain", "value": { "tag": "V1", "value": { "tag": "Unknown", "value": { "reason": "bulletin allowance is not available" } } } } } | +| `Preimage/submit` | ❌ | submit failed: { "error": { "tag": "Domain", "value": { "tag": "V1", "value": { "tag": "Unknown", "value": { "reason": "bulletin allowance is not available" } } } } } | +| `Resource Allocation/request` | ✅ | resource allocation result: { "outcomes": [ "Allocated", "NotAvailable" ] } | +| `Signing/create_transaction` | ✅ | transaction created: { "transaction": "0xd9018400f41df7581a7a4bdf59ab2497f3d86dd8ea14db35c5c1930790d5a3554d0bef1301ae9c35d29363cd548f24c435c1a71af4971b119f32e376af9dc15e658d29c70e65baa9dd8430ecb7eee566f821ab87aba43d39821174de067478e45dff81c58a00000000000000000000000000000000000000" } | +| `Signing/create_transaction_with_legacy_account` | ✅ | selected legacy account: { "publicKey": "0xf41df7581a7a4bdf59ab2497f3d86dd8ea14db35c5c1930790d5a3554d0bef13", "name": "pgherveou.06" } transaction created: { "transaction": "0xd9018400f41df7581a7a4bdf59ab2497f3d86dd8ea14db35c5c1930790d5a3554d0bef13012430b825adcbb1321b1310144a110809ae758cbc66b94d0... | +| `Signing/sign_raw_with_legacy_account` | ✅ | raw bytes signed: { "signature": "0x3af5d72c406e9279316f5ee707f4c320717ec72a55eb1ab80a04c36708079b3c486fc9102153c0dc5093d2630974302dc1ad6d129fe7024a137836a7331b8980" } | +| `Signing/sign_payload_with_legacy_account` | ✅ | payload signed: { "signature": "0x0061084213f1c30f5776f34ae6a84b14d5b1c3fc6ffca3b531986ae5456be523462d23f3da45e4f8c389c0bd55af3c3099be25da32bce68a8c5d605ccc1a4086" } | +| `Signing/sign_raw` | ✅ | raw bytes signed: { "signature": "0xd0afe46e7df6c2e032c3cb2fd923f96519aee31dda922770beba20c9d09e66389307bb1da61c53ea394e6babee235c852c1cd1a4af1d208153cdc06c767e2686" } | +| `Signing/sign_payload` | ✅ | payload signed: { "signature": "0x1eb6986df46f3347fb3054f8f2864f40eac4f03d43a05b2529a5b8e30fed1b4591da6ea79da89baf056bf4e94071d635ae0c32c5554d899d77cbe7e6a8d73986" } | +| `Statement Store/subscribe` | ✅ | submitting statement: { "expiry": "7661629886880022528n", "topics": [ "0xa962ad4e75e2fc9251c2fb585f98c83a69db2ce0cb99bbb7e0714591bdd9b1a6" ], "proof": { "tag": "Sr25519", "value": { "signature": "0xe6ec7fcffd0322d0bedc33ef99a491d1c6fd5a29b197d337e9bbb984309e544260098b3954cc936628f5deb82c51f5a95cc... | +| `Statement Store/create_proof` | ✅ | proof created: { "proof": { "tag": "Sr25519", "value": { "signature": "0x92b74641cd174206267af9a8bf11d09a20ab0a37924acc2018c386586b666f1e168831f7e126da6a139b7ef0809b2c286c7e89d4d7c5ff1cc800286f1b819486", "signer": "0xf41df7581a7a4bdf59ab2497f3d86dd8ea14db35c5c1930790d5a3554d0bef13" } } } | +| `Statement Store/submit` | ✅ | statement submitted | +| `Statement Store/create_proof_authorized` | ✅ | proof created: { "proof": { "tag": "Sr25519", "value": { "signature": "0x0e5ada3138607a38cf64e894cf50ccb2523b0de19a77f8bd7f984c39e6d71f38bc46b2fc7d2215610039f211f31e01bbf78b19d4caf25d7a8b481f2148bd618c", "signer": "0x60c724a9f56cb147403ae2ac1e7b55170ec8c29e127edc72dfb239431b03a379" } } } | +| `System/handshake` | ✅ | handshake succeeded | +| `System/feature_supported` | ✅ | feature supported: true | +| `System/navigate_to` | ✅ | navigation succeeded | +| `Theme/subscribe` | ✅ | theme received: { "name": { "tag": "Default" }, "variant": "Dark" } | diff --git a/hosts/dotli b/hosts/dotli index bcd3a424..df79ee14 160000 --- a/hosts/dotli +++ b/hosts/dotli @@ -1 +1 @@ -Subproject commit bcd3a424e5e40ed030adf79360d0fb714ae341da +Subproject commit df79ee147041a1b0db71e5773a9bc3aa3f8ac179 diff --git a/hosts/ios b/hosts/ios new file mode 160000 index 00000000..1adb56f5 --- /dev/null +++ b/hosts/ios @@ -0,0 +1 @@ +Subproject commit 1adb56f53d1551f996a76c628d2160d8425b4bc4 diff --git a/ios/truapi-host/.gitignore b/ios/truapi-host/.gitignore new file mode 100644 index 00000000..11cc1dd7 --- /dev/null +++ b/ios/truapi-host/.gitignore @@ -0,0 +1,4 @@ +.build/ +DerivedData/ +*.xcodeproj/xcuserdata/ +Package.resolved diff --git a/ios/truapi-host/Package.swift b/ios/truapi-host/Package.swift new file mode 100644 index 00000000..e7764729 --- /dev/null +++ b/ios/truapi-host/Package.swift @@ -0,0 +1,35 @@ +// swift-tools-version: 5.9 +// +// TrUAPI iOS host package. +// +// The `truapi_serverFFI` target wraps the UniFFI-generated C header + module +// map so the generated Swift bindings can `import truapi_serverFFI`. The +// `TrUAPIHost` target contains both the generated Swift bindings and the +// thin host shell defined in `TrUAPIHost.swift`. +// +// Consumers must link a prebuilt `libtruapi_server` static or dynamic +// library when integrating into their app target. This package does not +// vendor the binary itself; see README.md for build instructions. + +import PackageDescription + +let package = Package( + name: "TrUAPIHost", + platforms: [.iOS(.v16), .macOS(.v13)], + products: [ + .library(name: "TrUAPIHost", targets: ["TrUAPIHost"]), + ], + targets: [ + .systemLibrary( + name: "truapi_serverFFI", + path: "Sources/truapi_serverFFI/include", + pkgConfig: nil, + providers: [] + ), + .target( + name: "TrUAPIHost", + dependencies: ["truapi_serverFFI"], + path: "Sources/TrUAPIHost" + ), + ] +) diff --git a/ios/truapi-host/README.md b/ios/truapi-host/README.md new file mode 100644 index 00000000..d0975577 --- /dev/null +++ b/ios/truapi-host/README.md @@ -0,0 +1,204 @@ +# TrUAPI iOS host adapter + +*Thin Swift shell over the Rust TrUAPI core (UniFFI). Wire decoding, request routing, and subscription lifecycle stay in the Rust core; products connect through the localhost WebSocket bridge.* + +## What this package is for + +The public surface lives in [`Sources/TrUAPIHost/TrUAPIHost.swift`](Sources/TrUAPIHost/TrUAPIHost.swift): + +- `HostBridge` - callback bundle the embedding app implements. Split into device permissions, remote permissions, navigation, push, feature support, and scoped storage. +- `HostStorageBackend` - product-scoped read/write/clear protocol the host backs with its own persistence. +- `HostCoreStorageBackend` - core-owned read/write/clear protocol for auth session, pairing identity, and persisted permission decisions. +- `TrUAPIHostCore` - owning wrapper around the UniFFI-generated `NativeTrUApiCore`. Holds the bridge alive for the lifetime of the core and exposes the localhost WebSocket bridge, core-owned disconnect, and native change notifications for core storage, theme, and preimage updates. +- `LocalhostBridgeBootstrap` - helper that produces a JS snippet publishing the WS bridge endpoint to the product page so it can dial back in. + +The generated UniFFI bindings live alongside the shell in `Sources/TrUAPIHost/truapi_server.swift` and the C header / module map in `Sources/truapi_serverFFI/include/`. They are ignored build outputs; regenerate them before building or publishing the Swift package. + +## Architecture + +```text +product app in WKWebView + Uint8Array frames via @parity/truapi createWebSocketProvider + | + v ws://127.0.0.1:/?t= +TrUAPIHostCore.startWsBridge() + → libtruapi_server (tokio WS server) + → Rust dispatcher +``` + +The product running in the `WKWebView` opens a `WebSocket` to the localhost port + token returned by `startWsBridge`. From there the Rust core handles the wire protocol directly. Outbound responses and host-side capability callbacks (`navigateTo`, `pushNotification`, `cancelNotification`, `devicePermission`, `remotePermission`, `authStateChanged`, core storage, chain JSON-RPC, confirmations, preimage, theme, `featureSupported`, `storage`) reach the embedder through `HostBridge`. + +## Permissions split + +The core's `Permissions` platform trait has two methods, and so does the bridge: + +- `devicePermission(request:)` - OS-scoped grants (camera, mic, location, push). `request` is a SCALE-encoded `v01::HostDevicePermissionRequest`. +- `remotePermission(request:)` - per-product capability bundles. `request` is a SCALE-encoded `v01::RemotePermissionRequest`. + +Both return a `Bool` granted flag. SCALE decoding for the UI prompt is done by the `@parity/truapi` JS client (or any consumer that links the protocol crate's types directly). + +## Example + +> **Threading:** the Rust core invokes every `HostBridge` callback on a +> background thread it owns, never the main thread. Hop to the main thread +> (`DispatchQueue.main` / `MainActor`) before touching UIKit, WebKit, or the +> `WKWebView`. UI-decision callbacks (`navigateTo`, `devicePermission`, +> `remotePermission`, `confirmUserAction`, `submitPreimage`) each run on +> their own blocking-pool thread, so it is safe to use +> `DispatchQueue.main.sync` (or a semaphore) to present the prompt on the +> main thread and block the calling thread until the user decides; other +> TrUAPI traffic keeps flowing while you wait. The remaining callbacks (auth +> state, storage, core storage, chain, feature, theme, preimage lookups) run +> inline on the dispatcher thread and must return promptly without blocking. + +```swift +import Foundation +import WebKit +import TrUAPIHost + +final class MyStorage: HostStorageBackend, @unchecked Sendable { + private var map: [String: Data] = [:] + func read(key: String) throws -> Data? { map[key] } + func write(key: String, value: Data) throws { map[key] = value } + func clear(key: String) throws { map.removeValue(forKey: key) } +} + +final class MyCoreStorage: HostCoreStorageBackend, @unchecked Sendable { + private var map: [Data: Data] = [:] + func read(key: Data) throws -> Data? { map[key] } + func write(key: Data, value: Data) throws { map[key] = value } + func clear(key: Data) throws { map.removeValue(forKey: key) } +} + +final class MyBridge: HostBridge, @unchecked Sendable { + let storage: HostStorageBackend = MyStorage() + let coreStorage: HostCoreStorageBackend = MyCoreStorage() + + // Callbacks arrive on background threads, never the main thread. + // Hop to the main thread before touching UIKit/WebKit. + func navigateTo(url: String) throws { + DispatchQueue.main.async { /* UIApplication.shared.open(...) */ } + } + + func pushNotification(payload: Data) throws -> UInt32 { + let id: UInt32 = 1 + DispatchQueue.main.async { /* schedule notification */ } + return id + } + + func cancelNotification(id: UInt32) throws { + DispatchQueue.main.async { /* cancel notification */ } + } + + func devicePermission(request: Data) throws -> Bool { + // Called on a blocking-pool thread; present synchronously on the main + // thread and return the decision. Blocking here does not stall other + // TrUAPI traffic. + DispatchQueue.main.sync { /* show prompt; */ false } + } + + func remotePermission(request: Data) throws -> Bool { + DispatchQueue.main.sync { /* show prompt; */ false } + } + + // Core-owned auth state stream: render `.pairing` as the pairing QR + // sheet, `.connected`/`.disconnected` as the account badge, and + // `.loginFailed` as a retryable error. When the user closes the pairing + // sheet, report it with `core.cancelLogin()`. + func authStateChanged(state: AuthState) { + DispatchQueue.main.async { /* render the state */ } + } + + func featureSupported(request: Data) throws -> Bool { false } + + func chainConnect(genesisHash: Data) throws -> UInt32? { + let id: UInt32 = 1 + DispatchQueue.main.async { /* open JSON-RPC connection, forward responses via core.notifyChainResponse */ } + return id + } + + func chainSend(connectionId: UInt32, request: String) throws { + /* send JSON-RPC request on the host connection */ + } + + func chainClose(connectionId: UInt32) throws { + /* close host connection */ + } + + func confirmUserAction(review: Data) throws -> Bool { + DispatchQueue.main.sync { /* render decoded UserConfirmationReview; */ false } + } +} + +let bridge = MyBridge() +let runtimeConfig = RuntimeConfig( + productId: "my-product.dot", + hostName: "My Host", + hostIcon: "https://host.example/icon.png", + peopleChainGenesisHash: Data(repeating: 0, count: 32), + pairingDeeplinkScheme: .polkadotApp +) +let core = try TrUAPIHostCore(bridge: bridge, runtimeConfig: runtimeConfig) +let endpoint = try core.startWsBridge() + +// Call these from host/platform observers so native subscriptions see updates +// after their immediate current item. +core.notifySessionStoreChanged() +core.notifyThemeChanged(theme: .dark) +core.notifyPreimageChanged(key: preimageKey, value: preimageBytesOrNil) +core.notifyChainResponse(connectionId: chainConnectionId, json: jsonRpcResponse) +core.notifyChainClosed(connectionId: chainConnectionId) + +let contentController = WKUserContentController() +let bootstrapScript = LocalhostBridgeBootstrap.script(port: endpoint.port, token: endpoint.token) +let userScript = WKUserScript( + source: bootstrapScript, + injectionTime: .atDocumentStart, + forMainFrameOnly: true +) +contentController.addUserScript(userScript) + +let configuration = WKWebViewConfiguration() +configuration.userContentController = contentController +let webView = WKWebView(frame: .zero, configuration: configuration) +webView.load(URLRequest(url: URL(string: "https://your-product.example/")!)) + +// On logout: +core.disconnect() +``` + +The product page reads `window.__truapi_localhost.url` (set by the bootstrap script) and passes it to `@parity/truapi`'s `createWebSocketProvider(url)`. + +## Linking the cdylib + +This package does not vendor `libtruapi_server` - integrators link a prebuilt static or dynamic library when building the app target. Typical workflow: + +```bash +cargo build -p truapi-server --release --features ws-bridge \ + --target aarch64-apple-ios +cargo build -p truapi-server --release --features ws-bridge \ + --target aarch64-apple-ios-sim +``` + +Then either bundle the `.a` files as a `.xcframework` and add it under "Frameworks, Libraries, and Embedded Content" in the app target, or link directly via `OTHER_LDFLAGS`. + +## Regenerating the bindings + +The ignored bindings under `Sources/TrUAPIHost/truapi_server.swift` and `Sources/truapi_serverFFI/include/` are produced from the workspace `uniffi-bindgen-cli`. Regenerate them before building or publishing the Swift package. The CLI emits `truapi_server.swift`, `truapi_serverFFI.h`, and `truapi_serverFFI.modulemap` into a single output directory; the modulemap is renamed to `module.modulemap` and the header is colocated under `Sources/truapi_serverFFI/include/` so SwiftPM's `systemLibrary` target picks them up. + +```bash +cargo build -p truapi-server --release --features ws-bridge +mkdir -p /tmp/uniffi-swift-out +cargo run -p uniffi-bindgen-cli -- generate \ + --library target/release/libtruapi_server.so \ + --language swift \ + --out-dir /tmp/uniffi-swift-out +cp /tmp/uniffi-swift-out/truapi_server.swift \ + ios/truapi-host/Sources/TrUAPIHost/truapi_server.swift +cp /tmp/uniffi-swift-out/truapi_serverFFI.h \ + ios/truapi-host/Sources/truapi_serverFFI/include/truapi_serverFFI.h +cp /tmp/uniffi-swift-out/truapi_serverFFI.modulemap \ + ios/truapi-host/Sources/truapi_serverFFI/include/module.modulemap +``` + +Or run `make uniffi` from the repo root. diff --git a/ios/truapi-host/Sources/TrUAPIHost/TrUAPIHost.swift b/ios/truapi-host/Sources/TrUAPIHost/TrUAPIHost.swift new file mode 100644 index 00000000..72edb227 --- /dev/null +++ b/ios/truapi-host/Sources/TrUAPIHost/TrUAPIHost.swift @@ -0,0 +1,574 @@ +// TrUAPIHost - iOS host adapter. +// +// The Rust core (compiled to `libtruapi_server`, surfaced through UniFFI in +// the sibling `truapi_server.swift` file) owns wire decoding, request +// routing, subscription lifecycle, and platform trait dispatch. +// +// This file exposes: +// +// * `HostBridge` - a Swift-friendly callback bundle the embedding app +// implements. It splits device and remote permissions, mirroring the +// `Permissions` platform trait in the Rust core. +// * `TrUAPIHostCore` - owning wrapper around the UniFFI-generated +// `NativeTrUApiCore`. Holds the bridge alive for the lifetime of the +// core and exposes session + WS-bridge controls. +// * `LocalhostBridgeBootstrap` - small JS snippet that publishes the WS +// bridge endpoint to the product page so it can dial back in. +// +// Products running inside a `WKWebView` connect to the Rust core via the +// localhost WebSocket bridge. The bootstrap script publishes the URL +// (`ws://127.0.0.1:/?t=`) and a MessagePort-shaped compatibility +// object that proxies the product's existing webview transport onto it. + +import Foundation + +/// Package metadata. +public enum TrUAPIHost { + public static let version = "0.1.0" +} + +/// Deeplink scheme used when the Rust core builds SSO pairing payloads. +public enum PairingDeeplinkScheme: Sendable { + case polkadotApp + case polkadotAppDev + + fileprivate var native: NativePairingDeeplinkScheme { + switch self { + case .polkadotApp: + return .polkadotApp + case .polkadotAppDev: + return .polkadotAppDev + } + } +} + +/// Static product and pairing config supplied before the Rust core handles +/// product calls. One core instance represents one product identity. +/// +/// `hostName`, `hostIcon`, `hostVersion`, `platformType`, and +/// `platformVersion` describe the host to the wallet during SSO pairing. +/// `peopleChainGenesisHash` and `bulletinChainGenesisHash` must each be +/// exactly 32 bytes. +public struct RuntimeConfig: Sendable { + public let productId: String + public let hostName: String + public let hostIcon: String? + public let hostVersion: String? + public let platformType: String? + public let platformVersion: String? + public let peopleChainGenesisHash: Data + public let bulletinChainGenesisHash: Data + public let localSessionSecret: Data? + public let localSessionLiteUsername: String? + public let pairingDeeplinkScheme: PairingDeeplinkScheme + + public init( + productId: String, + hostName: String, + hostIcon: String? = nil, + hostVersion: String? = nil, + platformType: String? = nil, + platformVersion: String? = nil, + peopleChainGenesisHash: Data, + bulletinChainGenesisHash: Data, + localSessionSecret: Data? = nil, + localSessionLiteUsername: String? = nil, + pairingDeeplinkScheme: PairingDeeplinkScheme = .polkadotApp + ) { + self.productId = productId + self.hostName = hostName + self.hostIcon = hostIcon + self.hostVersion = hostVersion + self.platformType = platformType + self.platformVersion = platformVersion + self.peopleChainGenesisHash = peopleChainGenesisHash + self.bulletinChainGenesisHash = bulletinChainGenesisHash + self.localSessionSecret = localSessionSecret + self.localSessionLiteUsername = localSessionLiteUsername + self.pairingDeeplinkScheme = pairingDeeplinkScheme + } + + fileprivate var native: NativeRuntimeConfig { + NativeRuntimeConfig( + productId: productId, + hostName: hostName, + hostIcon: hostIcon, + hostVersion: hostVersion, + platformType: platformType, + platformVersion: platformVersion, + peopleChainGenesisHash: peopleChainGenesisHash, + bulletinChainGenesisHash: bulletinChainGenesisHash, + localSessionSecret: localSessionSecret, + localSessionLiteUsername: localSessionLiteUsername, + pairingDeeplinkScheme: pairingDeeplinkScheme.native + ) + } +} + +/// Bootstrap helper for the native localhost WebSocket bridge that the Rust +/// core stands up via `NativeTrUApiCore.startWsBridge(bindPort:)` when the +/// cdylib is built with the `ws-bridge` feature. +public enum LocalhostBridgeBootstrap { + /// Returns a `