diff --git a/.github/actions/LICENSE b/.github/actions/LICENSE new file mode 100644 index 00000000..6779f0ec --- /dev/null +++ b/.github/actions/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2023 Luke Parker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.github/actions/bitcoin/action.yml b/.github/actions/bitcoin/action.yml new file mode 100644 index 00000000..4aad4791 --- /dev/null +++ b/.github/actions/bitcoin/action.yml @@ -0,0 +1,41 @@ +name: bitcoin-regtest +description: Spawns a regtest Bitcoin daemon + +inputs: + version: + description: "Version to download and run" + required: false + default: 24.0.1 + +runs: + using: "composite" + steps: + - name: Bitcoin Daemon Cache + id: cache-bitcoind + uses: actions/cache@v3 + with: + path: bitcoind + key: bitcoind-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} + + - name: Download the Bitcoin Daemon + if: steps.cache-bitcoind.outputs.cache-hit != 'true' + shell: bash + run: | + RUNNER_OS=linux + RUNNER_ARCH=x86_64 + + BASE=bitcoin-${{ inputs.version }} + FILE=$BASE-$RUNNER_ARCH-$RUNNER_OS-gnu.tar.gz + wget https://bitcoincore.org/bin/bitcoin-core-${{ inputs.version }}/$FILE + tar xzvf $FILE + + cd bitcoin-${{ inputs.version }} + sudo mv bin/* /bin && sudo mv lib/* /lib + + - name: Bitcoin Regtest Daemon + shell: bash + run: | + RPC_USER=serai + RPC_PASS=seraidex + + bitcoind -regtest -rpcuser=$RPC_USER -rpcpassword=$RPC_PASS -daemon diff --git a/.github/actions/build-dependencies/action.yml b/.github/actions/build-dependencies/action.yml index 15db381e..754daea3 100644 --- a/.github/actions/build-dependencies/action.yml +++ b/.github/actions/build-dependencies/action.yml @@ -21,7 +21,7 @@ runs: using: "composite" steps: - name: Install Protobuf - uses: arduino/setup-protoc@v1 + uses: arduino/setup-protoc@master with: repo-token: ${{ inputs.github-token }} @@ -33,7 +33,7 @@ runs: solc-select use 0.8.16 - name: Install Rust - uses: ./.github/actions/cached-rust + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ inputs.rust-toolchain }} components: ${{ inputs.rust-components }} @@ -44,8 +44,7 @@ runs: run: echo "version=$(cat .github/nightly-version)" >> $GITHUB_OUTPUT - name: Install WASM toolchain - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ steps.nightly.outputs.version }} - profile: minimal - target: wasm32-unknown-unknown + targets: wasm32-unknown-unknown diff --git a/.github/actions/cached-rust/action.yml b/.github/actions/cached-rust/action.yml deleted file mode 100644 index 09ae995e..00000000 --- a/.github/actions/cached-rust/action.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: cached-rust -description: Installs Rust, caching ~/.cargo and ./target - -inputs: - toolchain: - description: "Toolchain to install" - required: false - default: stable - - components: - description: "Components to install" - required: false - default: - -runs: - using: "composite" - steps: - - name: Rust Cache - uses: actions/cache@v3 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ./target - key: ${{ runner.os }}-${{ runner.arch }}-rust-${{ steps.install-rust.outputs.rustc_hash }}-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-${{ runner.arch }}-rust-${{ steps.install-rust.outputs.rustc_hash }}- - - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{ inputs.toolchain }} - profile: minimal - default: true - components: ${{ inputs.components }} diff --git a/.github/actions/monero-wallet-rpc/action.yml b/.github/actions/monero-wallet-rpc/action.yml new file mode 100644 index 00000000..ebbd2171 --- /dev/null +++ b/.github/actions/monero-wallet-rpc/action.yml @@ -0,0 +1,44 @@ +name: monero-wallet-rpc +description: Spawns a Monero Wallet-RPC. + +inputs: + version: + description: "Version to download and run" + required: false + default: v0.18.1.2 + +runs: + using: "composite" + steps: + - name: Monero Wallet RPC Cache + id: cache-monero-wallet-rpc + uses: actions/cache@v3 + with: + path: monero-wallet-rpc + key: monero-wallet-rpc-${{ runner.os }}-${{ runner.arch }}-${{ inputs.version }} + + - name: Download the Monero Wallet RPC + if: steps.cache-monero-wallet-rpc.outputs.cache-hit != 'true' + # Calculates OS/ARCH to demonstrate it, yet then locks to linux-x64 due + # to the contained folder not following the same naming scheme and + # requiring further expansion not worth doing right now + shell: bash + run: | + RUNNER_OS=${{ runner.os }} + RUNNER_ARCH=${{ runner.arch }} + + RUNNER_OS=${RUNNER_OS,,} + RUNNER_ARCH=${RUNNER_ARCH,,} + + RUNNER_OS=linux + RUNNER_ARCH=x64 + + FILE=monero-$RUNNER_OS-$RUNNER_ARCH-${{ inputs.version }}.tar.bz2 + wget https://downloads.getmonero.org/cli/$FILE + tar -xvf $FILE + + mv monero-x86_64-linux-gnu-${{ inputs.version }}/monero-wallet-rpc monero-wallet-rpc + + - name: Monero Wallet RPC + shell: bash + run: ./monero-wallet-rpc --disable-rpc-login --rpc-bind-port 6061 --allow-mismatched-daemon-version --wallet-dir ./ --detach diff --git a/.github/actions/monero/action.yml b/.github/actions/monero/action.yml index 10ec5056..8985a548 100644 --- a/.github/actions/monero/action.yml +++ b/.github/actions/monero/action.yml @@ -5,7 +5,7 @@ inputs: version: description: "Version to download and run" required: false - default: v0.18.0.0 + default: v0.18.1.2 runs: using: "composite" diff --git a/.github/actions/test-dependencies/action.yml b/.github/actions/test-dependencies/action.yml index 9af81eef..2fb500d7 100644 --- a/.github/actions/test-dependencies/action.yml +++ b/.github/actions/test-dependencies/action.yml @@ -12,6 +12,16 @@ inputs: required: false default: v0.18.0.0 + bitcoin-version: + description: "Bitcoin version to download and run as a regtest node" + required: false + default: 24.0.1 + + serai: + description: "Run a Serai development node in the background" + required: false + default: false + runs: using: "composite" steps: @@ -29,3 +39,21 @@ runs: uses: ./.github/actions/monero with: version: ${{ inputs.monero-version }} + + - name: Run a Bitcoin Regtest Node + uses: ./.github/actions/bitcoin + with: + version: ${{ inputs.bitcoin-version }} + + - name: Run a Monero Wallet-RPC + uses: ./.github/actions/monero-wallet-rpc + + - name: Run a Serai Development Node + if: ${{ inputs.serai }} + shell: bash + run: | + cd substrate/node + cargo build + cd ../.. + + ./target/debug/serai-node --dev & diff --git a/.github/nightly-version b/.github/nightly-version index e9bf8776..d6ab1143 100644 --- a/.github/nightly-version +++ b/.github/nightly-version @@ -1 +1 @@ -nightly-2022-12-01 +nightly-2023-02-01 diff --git a/.github/workflows/daily-deny.yml b/.github/workflows/daily-deny.yml index 01e8e6a7..460f4b5a 100644 --- a/.github/workflows/daily-deny.yml +++ b/.github/workflows/daily-deny.yml @@ -18,10 +18,7 @@ jobs: key: rust-advisory-db - name: Install cargo - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - profile: minimal + uses: dtolnay/rust-toolchain@stable - name: Install cargo deny run: cargo install --locked cargo-deny diff --git a/.github/workflows/monero-tests.yaml b/.github/workflows/monero-tests.yaml index d5c66acc..37595084 100644 --- a/.github/workflows/monero-tests.yaml +++ b/.github/workflows/monero-tests.yaml @@ -33,7 +33,7 @@ jobs: # Test against all supported protocol versions strategy: matrix: - version: [v0.17.3.2, v0.18.0.0] + version: [v0.17.3.2, v0.18.1.2] steps: - uses: actions/checkout@v3 @@ -50,7 +50,7 @@ jobs: - name: Run Integration Tests # Don't run if the the tests workflow also will - if: ${{ matrix.version != 'v0.18.0.0' }} + if: ${{ matrix.version != 'v0.18.1.2' }} run: | cargo test --package monero-serai --all-features --test '*' cargo test --package serai-processor monero diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 07581c51..0cf8c04c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,7 +26,7 @@ jobs: rust-components: clippy - name: Run Clippy - run: cargo clippy --all-features --tests -- -D warnings -A dead_code + run: cargo clippy --all-features --all-targets -- -D warnings -A dead_code deny: runs-on: ubuntu-latest @@ -40,10 +40,7 @@ jobs: key: rust-advisory-db - name: Install cargo - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - profile: minimal + uses: dtolnay/rust-toolchain@stable - name: Install cargo deny run: cargo install --locked cargo-deny @@ -61,8 +58,13 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Build node + run: | + cd substrate/node + cargo build + - name: Run Tests - run: cargo test --all-features + run: GITHUB_CI=true cargo test --all-features fmt: runs-on: ubuntu-latest @@ -73,12 +75,10 @@ jobs: id: nightly run: echo "version=$(cat .github/nightly-version)" >> $GITHUB_OUTPUT - # Doesn't grab the cache as it's not needed - name: Install rustfmt - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ steps.nightly.outputs.version }} - profile: minimal components: rustfmt - name: Run rustfmt diff --git a/Cargo.lock b/Cargo.lock index ee05a685..75b622ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -27,7 +27,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli 0.27.0", + "gimli 0.27.2", ] [[package]] @@ -36,6 +36,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array 0.14.6", +] + [[package]] name = "aead" version = "0.4.3" @@ -43,6 +52,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" dependencies = [ "generic-array 0.14.6", + "rand_core 0.6.4", +] + +[[package]] +name = "aead" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" +dependencies = [ + "crypto-common", + "generic-array 0.14.6", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher 0.2.5", ] [[package]] @@ -64,7 +95,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" dependencies = [ "cfg-if", - "cipher 0.4.3", + "cipher 0.4.4", "cpufeatures", ] @@ -74,14 +105,48 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" dependencies = [ - "aead", + "aead 0.4.3", "aes 0.7.5", "cipher 0.3.0", "ctr 0.8.0", - "ghash", + "ghash 0.4.4", "subtle", ] +[[package]] +name = "aes-gcm" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" +dependencies = [ + "aead 0.5.1", + "aes 0.8.2", + "cipher 0.4.4", + "ctr 0.9.2", + "ghash 0.5.0", + "subtle", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + [[package]] name = "ahash" version = "0.7.6" @@ -93,6 +158,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom 0.2.8", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.20" @@ -122,9 +199,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800" [[package]] name = "approx" @@ -136,15 +213,16 @@ dependencies = [ ] [[package]] -name = "array-bytes" -version = "4.1.0" -source = "git+https://github.com/hack-ink/array-bytes?rev=994cd29b66bd2ab5c8c15f0b15a1618d4bb2d94c#994cd29b66bd2ab5c8c15f0b15a1618d4bb2d94c" +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] -name = "array-init" -version = "2.1.0" +name = "array-bytes" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" +checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" [[package]] name = "arrayref" @@ -173,52 +251,79 @@ dependencies = [ "term", ] +[[package]] +name = "asn1-rs" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ff05a702273012438132f449575dbc804e27b2f3cbe3069aa237d26c98fa33" +dependencies = [ + "asn1-rs-derive 0.1.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time 0.3.20", +] + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive 0.4.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time 0.3.20", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8b7511298d5b7784b40b092d9e9dcd3a627a5707e4b5e507931ab0d44eeebf" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "asn1_der" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e22d1f4b888c298a027c99dc9048015fac177587de20fc30232a057dfbe24a21" -[[package]] -name = "async-channel" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" -dependencies = [ - "async-lock", - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" -dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-lock", - "blocking", - "futures-lite", - "once_cell", -] - [[package]] name = "async-io" version = "1.12.0" @@ -241,85 +346,18 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" dependencies = [ "event-listener", - "futures-lite", ] -[[package]] -name = "async-process" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6381ead98388605d0d9ff86371043b5aa922a3905824244de40dc263a14fcba4" -dependencies = [ - "async-io", - "async-lock", - "autocfg", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "libc", - "signal-hook", - "windows-sys 0.42.0", -] - -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" -dependencies = [ - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "once_cell", - "pin-project-lite 0.2.9", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-std-resolver" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba50e24d9ee0a8950d3d03fc6d0dd10aa14b5de3b101949b4e160f7fee7c723" -dependencies = [ - "async-std", - "async-trait", - "futures-io", - "futures-util", - "pin-utils", - "socket2", - "trust-dns-resolver", -] - -[[package]] -name = "async-task" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" - [[package]] name = "async-trait" -version = "0.1.60" +version = "0.1.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" +checksum = "b84f9ebcc6c1f5b8cb160f6990096a5c127f423fcb6e1ccc46c370cbdfb75dfc" dependencies = [ "proc-macro2", "quote", @@ -334,7 +372,7 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -352,9 +390,9 @@ dependencies = [ [[package]] name = "atomic-waker" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" [[package]] name = "atty" @@ -408,7 +446,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.30.0", + "object 0.30.3", "rustc-demangle", ] @@ -469,10 +507,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] -name = "base64ct" -version = "1.5.3" +name = "base64" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bech32" @@ -480,6 +524,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "beef" version = "0.5.2" @@ -500,9 +550,9 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.60.1" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ "bitflags", "cexpr", @@ -515,6 +565,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", + "syn", ] [[package]] @@ -532,6 +583,46 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[package]] +name = "bitcoin" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" +dependencies = [ + "bech32 0.9.1", + "bitcoin_hashes", + "secp256k1", + "serde", +] + +[[package]] +name = "bitcoin-serai" +version = "0.1.0" +dependencies = [ + "bitcoin", + "flexible-transcript", + "hex", + "k256", + "lazy_static", + "modular-frost", + "rand_core 0.6.4", + "reqwest", + "secp256k1", + "serde", + "serde_json", + "sha2 0.10.6", + "thiserror", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90064b8dee6815a6470d60bad07bbbaee885c0e12d04177138fa3291a01b7bc4" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -571,24 +662,24 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq 0.1.5", + "constant_time_eq 0.2.4", ] [[package]] name = "blake2s_simd" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db539cc2b5f6003621f1cd9ef92d7ded8ea5232c7de0f9faa2de251cd98730d4" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" dependencies = [ "arrayref", "arrayvec 0.7.2", - "constant_time_eq 0.1.5", + "constant_time_eq 0.2.4", ] [[package]] @@ -610,7 +701,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding", + "block-padding 0.1.5", "byte-tools", "byteorder", "generic-array 0.12.4", @@ -627,13 +718,23 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array 0.14.6", ] +[[package]] +name = "block-modes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" +dependencies = [ + "block-padding 0.2.1", + "cipher 0.2.5", +] + [[package]] name = "block-padding" version = "0.1.5" @@ -644,17 +745,21 @@ dependencies = [ ] [[package]] -name = "blocking" -version = "1.3.0" +name = "block-padding" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "bounded-collections" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a071c348a5ef6da1d3a87166b408170b46002382b1dda83992b5c2208cefb370" dependencies = [ - "async-channel", - "async-lock", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", + "log", + "parity-scale-codec", + "scale-info", + "serde", ] [[package]] @@ -665,11 +770,12 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bstr" -version = "0.2.17" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "5ffdb39cb703212f3c11973452c2861b972f757b021158f3516ba10f2fa8b2c1" dependencies = [ "memchr", + "serde", ] [[package]] @@ -683,9 +789,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byte-slice-cast" @@ -699,6 +805,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + [[package]] name = "byteorder" version = "1.4.3" @@ -707,18 +819,18 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" dependencies = [ "serde", ] [[package]] name = "bzip2" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" dependencies = [ "bzip2-sys", "libc", @@ -737,9 +849,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.1" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad0e1e3e88dd237a156ab9f571021b8a158caa0ae44b1968a241efb5144c1e" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" dependencies = [ "serde", ] @@ -755,22 +867,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.14.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.16", - "serde", - "serde_json", -] - -[[package]] -name = "cargo_metadata" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982a0cf6a99c350d7246035613882e376d58cebe571785abc5da4f648d53ac0a" +checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" dependencies = [ "camino", "cargo-platform", @@ -782,13 +881,24 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" dependencies = [ "jobserver", ] +[[package]] +name = "ccm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca1a8fbc20b50ac9673ff014abfb2b5f4085ee1a850d408f14a159c5853ac7" +dependencies = [ + "aead 0.3.2", + "cipher 0.2.5", + "subtle", +] + [[package]] name = "cexpr" version = "0.6.0" @@ -838,7 +948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08" dependencies = [ "cfg-if", - "cipher 0.4.3", + "cipher 0.4.4", "cpufeatures", ] @@ -848,7 +958,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" dependencies = [ - "aead", + "aead 0.4.3", "chacha20 0.8.2", "cipher 0.3.0", "poly1305", @@ -865,6 +975,7 @@ dependencies = [ "js-sys", "num-integer", "num-traits", + "serde", "time 0.1.45", "wasm-bindgen", "winapi", @@ -878,11 +989,20 @@ checksum = "f6ed9c8b2d17acb8110c46f1da5bf4a696d745e1474a16db0cd2b49cd0249bf2" dependencies = [ "core2", "multibase", - "multihash", + "multihash 0.16.3", "serde", "unsigned-varint", ] +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array 0.14.6", +] + [[package]] name = "cipher" version = "0.3.0" @@ -894,9 +1014,9 @@ dependencies = [ [[package]] name = "cipher" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", @@ -927,9 +1047,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" dependencies = [ "glob", "libc", @@ -955,13 +1075,13 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.30" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656ad1e55e23d287773f7d8192c300dc715c3eeded93b3da651d11c42cfd74d2" +checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" dependencies = [ "bitflags", - "clap_derive 4.0.21", - "clap_lex 0.3.0", + "clap_derive 4.1.8", + "clap_lex 0.3.2", "is-terminal", "once_cell", "strsim", @@ -974,7 +1094,7 @@ version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro-error", "proc-macro2", "quote", @@ -983,11 +1103,11 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro-error", "proc-macro2", "quote", @@ -1005,9 +1125,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" dependencies = [ "os_str_bytes", ] @@ -1066,7 +1186,7 @@ checksum = "c94090a6663f224feae66ab01e41a2555a8296ee07b5f20dab8888bdefc9f617" dependencies = [ "base58check", "base64 0.12.3", - "bech32", + "bech32 0.7.3", "blake2", "digest 0.10.6", "generic-array 0.14.6", @@ -1081,9 +1201,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "6.1.3" +version = "6.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e621e7e86c46fd8a14c32c6ae3cb95656621b4743a27d0cffedb831d46e7ad21" +checksum = "6e7b787b0dc42e8111badfdbe4c3059158ccb2db8780352fa1b01e8ccf45cc4d" dependencies = [ "strum", "strum_macros", @@ -1092,9 +1212,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" dependencies = [ "crossbeam-utils", ] @@ -1116,22 +1236,21 @@ dependencies = [ [[package]] name = "console" -version = "0.15.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c" +checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" dependencies = [ "encode_unicode", "lazy_static", "libc", - "terminal_size", - "winapi", + "windows-sys 0.42.0", ] [[package]] name = "const-oid" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "constant_time_eq" @@ -1199,18 +1318,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.88.2" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52056f6d0584484b57fa6c1a65c1fcb15f3780d8b6a758426d9e3084169b2ddd" +checksum = "a7379abaacee0f14abf3204a7606118f0465785252169d186337bcb75030815a" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.88.2" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fed94c8770dc25d01154c3ffa64ed0b3ba9d583736f305fed7beebe5d9cf74" +checksum = "9489fa336927df749631f1008007ced2871068544f40a202ce6d93fbf2366a7b" dependencies = [ "arrayvec 0.7.2", "bumpalo", @@ -1220,6 +1339,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli 0.26.2", + "hashbrown 0.12.3", "log", "regalloc2", "smallvec", @@ -1228,33 +1348,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.88.2" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c451b81faf237d11c7e4f3165eeb6bac61112762c5cfe7b4c0fb7241474358f" +checksum = "05bbb67da91ec721ed57cef2f7c5ef7728e1cd9bde9ffd3ef8601022e73e3239" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.88.2" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c940133198426d26128f08be2b40b0bd117b84771fd36798969c4d712d81fc" +checksum = "418ecb2f36032f6665dc1a5e2060a143dbab41d83b784882e97710e890a7a16d" [[package]] name = "cranelift-entity" -version = "0.88.2" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87a0f1b2fdc18776956370cf8d9b009ded3f855350c480c1c52142510961f352" +checksum = "7cf583f7b093f291005f9fb1323e2c37f6ee4c7909e39ce016b2e8360d461705" dependencies = [ "serde", ] [[package]] name = "cranelift-frontend" -version = "0.88.2" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34897538b36b216cc8dd324e73263596d51b8cf610da6498322838b2546baf8a" +checksum = "0b66bf9e916f57fbbd0f7703ec6286f4624866bf45000111627c70d272c8dda1" dependencies = [ "cranelift-codegen", "log", @@ -1264,15 +1384,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.88.2" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b2629a569fae540f16a76b70afcc87ad7decb38dc28fa6c648ac73b51e78470" +checksum = "649782a39ce99798dd6b4029e2bb318a2fbeaade1b4fa25330763c10c65bc358" [[package]] name = "cranelift-native" -version = "0.88.2" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20937dab4e14d3e225c5adfc9c7106bafd4ac669bdb43027b911ff794c6fb318" +checksum = "937e021e089c51f9749d09e7ad1c4f255c2f8686cb8c3df63a34b3ec9921bc41" dependencies = [ "cranelift-codegen", "libc", @@ -1281,9 +1401,9 @@ dependencies = [ [[package]] name = "cranelift-wasm" -version = "0.88.2" +version = "0.93.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fc2288957a94fd342a015811479de1837850924166d1f1856d8406e6f3609b" +checksum = "d850cf6775477747c9dfda9ae23355dd70512ffebc70cf82b85a5b111ae668b5" dependencies = [ "cranelift-codegen", "cranelift-entity", @@ -1295,6 +1415,21 @@ dependencies = [ "wasmtime-types", ] +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + [[package]] name = "crc32fast" version = "1.3.2" @@ -1306,9 +1441,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if", "crossbeam-utils", @@ -1316,9 +1451,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -1327,22 +1462,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.7.1", + "memoffset 0.8.0", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] @@ -1372,6 +1507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.6", + "rand_core 0.6.4", "typenum", ] @@ -1395,16 +1531,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "ctr" version = "0.8.0" @@ -1420,7 +1546,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ - "cipher 0.4.3", + "cipher 0.4.4", ] [[package]] @@ -1445,15 +1571,16 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", + "serde", "subtle", "zeroize", ] [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.5" +version = "4.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67bc65846be335cb20f4e52d49a437b773a2c1fdb42b19fc84e79e6f6771536f" +checksum = "8da00a7a9a4eb92a0a0f8e75660926d48f0d0f3c537e455c457bcdaa1e16b1ac" dependencies = [ "cfg-if", "fiat-crypto", @@ -1465,9 +1592,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.85" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5add3fc1717409d029b20c5b6903fc0c0b02fa6741d820054f4a2efa5e5816fd" +checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" dependencies = [ "cc", "cxxbridge-flags", @@ -1477,9 +1604,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.85" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c87959ba14bc6fbc61df77c3fcfe180fc32b93538c4f1031dd802ccb5f2ff0" +checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" dependencies = [ "cc", "codespan-reporting", @@ -1492,15 +1619,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.85" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69a3e162fde4e594ed2b07d0f83c6c67b745e7f28ce58c6df5e6b6bef99dfb59" +checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" [[package]] name = "cxxbridge-macro" -version = "1.0.85" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6" +checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" dependencies = [ "proc-macro2", "quote", @@ -1523,6 +1650,41 @@ dependencies = [ "zeroize", ] +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "data-encoding" version = "2.3.3" @@ -1556,9 +1718,91 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] +[[package]] +name = "der-parser" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe398ac75057914d7d07307bf67dc7f3f574a26783b4fc7805a20ffa9f506e82" +dependencies = [ + "asn1-rs 0.3.1", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs 0.5.2", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive-syn-parse" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" +dependencies = [ + "derive_builder_core", + "syn", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -1618,7 +1862,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ - "block-buffer 0.10.3", + "block-buffer 0.10.4", "crypto-common", "subtle", ] @@ -1687,6 +1931,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dkg" version = "0.2.0" @@ -1721,16 +1976,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "dns-parser" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" -dependencies = [ - "byteorder", - "quick-error", -] - [[package]] name = "downcast" version = "0.11.0" @@ -1745,9 +1990,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dtoa" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00704156a7de8df8da0911424e30c2049957b0a714542a44e05fe693dd85313" +checksum = "65d09067bfacaa79114679b279d7f5885b53295b1e2cfb4e79c8e4bd3d633169" [[package]] name = "dunce" @@ -1778,9 +2023,9 @@ dependencies = [ [[package]] name = "dyn-clone" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9b0705efd4599c15a38151f4721f7bc388306f61084d3bfd50bd07fbca5cb60" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" [[package]] name = "ecdsa" @@ -1808,9 +2053,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ "signature 1.6.4", ] @@ -1836,7 +2081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" dependencies = [ "curve25519-dalek 3.2.0", - "hashbrown", + "hashbrown 0.12.3", "hex", "rand_core 0.6.4", "sha2 0.9.9", @@ -1845,9 +2090,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "elliptic-curve" @@ -1862,6 +2107,8 @@ dependencies = [ "ff", "generic-array 0.14.6", "group", + "hkdf", + "pem-rfc7468", "pkcs8", "rand_core 0.6.4", "sec1", @@ -1871,9 +2118,9 @@ dependencies = [ [[package]] name = "ena" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" +checksum = "b2e5d13ca2353ab7d0230988629def93914a8c4015f621f9b13ed2955614731d" dependencies = [ "log", ] @@ -1886,9 +2133,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if", ] @@ -1899,7 +2146,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn", @@ -1907,12 +2154,12 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" dependencies = [ - "atty", "humantime", + "is-terminal", "log", "regex", "termcolor", @@ -1964,7 +2211,7 @@ dependencies = [ "sha2 0.10.6", "sha3", "thiserror", - "uuid", + "uuid 0.8.2", ] [[package]] @@ -1991,10 +2238,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", - "fixed-hash", + "fixed-hash 0.8.0", "impl-codec", "impl-rlp", - "impl-serde 0.4.0", + "impl-serde", "scale-info", "tiny-keccak", ] @@ -2025,10 +2272,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" dependencies = [ "ethbloom", - "fixed-hash", + "fixed-hash 0.8.0", "impl-codec", "impl-rlp", - "impl-serde 0.4.0", + "impl-serde", "primitive-types", "scale-info", "uint", @@ -2129,7 +2376,7 @@ checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" dependencies = [ "arrayvec 0.7.2", "bytes", - "cargo_metadata 0.15.2", + "cargo_metadata", "chrono", "convert_case", "elliptic-curve", @@ -2319,9 +2566,9 @@ checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] @@ -2358,15 +2605,15 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" +checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955" [[package]] name = "file-per-thread-logger" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e16290574b39ee41c71aeb90ae960c504ebaf1e2a1c87bd52aa56ed6e1a02f" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" dependencies = [ "env_logger", "log", @@ -2374,21 +2621,21 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if", "libc", "redox_syscall", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] name = "finality-grandpa" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22349c6a11563a202d95772a68e0fcf56119e74ea8a2a19cf2301460fcd0df5" +checksum = "e24e6c429951433ccb7c87fd528c60084834dcd14763182c1f83291bcde24c34" dependencies = [ "either", "futures", @@ -2400,6 +2647,18 @@ dependencies = [ "scale-info", ] +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixed-hash" version = "0.8.0" @@ -2472,7 +2731,7 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "parity-scale-codec", ] @@ -2495,9 +2754,10 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "frame-support", + "frame-support-procedural", "frame-system", "linregress", "log", @@ -2513,33 +2773,31 @@ dependencies = [ "sp-runtime-interface", "sp-std", "sp-storage", + "static_assertions", ] [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.0.30", + "clap 4.1.8", "comfy-table", "frame-benchmarking", "frame-support", "frame-system", "gethostname", "handlebars", - "hash-db", "itertools", - "kvdb", "lazy_static", "linked-hash-map", "log", - "memory-db", "parity-scale-codec", "rand 0.8.5", - "rand_pcg 0.3.1", + "rand_pcg", "sc-block-builder", "sc-cli", "sc-client-api", @@ -2549,7 +2807,6 @@ dependencies = [ "sc-sysinfo", "serde", "serde_json", - "serde_nanos", "sp-api", "sp-blockchain", "sp-core", @@ -2562,7 +2819,6 @@ dependencies = [ "sp-std", "sp-storage", "sp-trie", - "tempfile", "thiserror", "thousands", ] @@ -2570,7 +2826,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "frame-support", "frame-system", @@ -2598,7 +2854,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "bitflags", "frame-metadata", @@ -2630,10 +2886,11 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "Inflector", "cfg-expr", + "derive-syn-parse", "frame-support-procedural-tools", "itertools", "proc-macro2", @@ -2644,7 +2901,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -2656,7 +2913,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "proc-macro2", "quote", @@ -2666,7 +2923,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "frame-support", "log", @@ -2684,7 +2941,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "parity-scale-codec", "sp-api", @@ -2700,12 +2957,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "fs_extra" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" - [[package]] name = "funty" version = "2.0.0" @@ -2714,9 +2965,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" dependencies = [ "futures-channel", "futures-core", @@ -2729,9 +2980,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" dependencies = [ "futures-core", "futures-sink", @@ -2739,15 +2990,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" dependencies = [ "futures-core", "futures-task", @@ -2757,9 +3008,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" [[package]] name = "futures-lite" @@ -2788,9 +3039,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" dependencies = [ "proc-macro2", "quote", @@ -2804,21 +3055,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" dependencies = [ "futures-io", - "rustls", - "webpki", + "rustls 0.20.8", + "webpki 0.22.0", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" [[package]] name = "futures-timer" @@ -2828,9 +3079,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" dependencies = [ "futures-channel", "futures-core", @@ -2889,10 +3140,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", - "wasm-bindgen", ] [[package]] @@ -2915,7 +3164,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" dependencies = [ "opaque-debug 0.3.0", - "polyval", + "polyval 0.5.3", +] + +[[package]] +name = "ghash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +dependencies = [ + "opaque-debug 0.3.0", + "polyval 0.6.0", ] [[package]] @@ -2931,21 +3190,21 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.0" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "glob" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", "bstr", @@ -2954,18 +3213,6 @@ dependencies = [ "regex", ] -[[package]] -name = "gloo-timers" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c4a8d6391675c6b2ee1a6c8d06e8e2d03605c44cec1270675985a4c2a5500b" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "group" version = "0.12.1" @@ -2979,9 +3226,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" dependencies = [ "bytes", "fnv", @@ -3031,7 +3278,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", ] [[package]] @@ -3045,9 +3301,18 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -3067,6 +3332,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "hex" version = "0.4.3" @@ -3141,9 +3412,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -3161,6 +3432,12 @@ dependencies = [ "pin-project-lite 0.2.9", ] +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + [[package]] name = "httparse" version = "1.8.0" @@ -3181,9 +3458,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" dependencies = [ "bytes", "futures-channel", @@ -3212,10 +3489,11 @@ dependencies = [ "http", "hyper", "log", - "rustls", + "rustls 0.20.8", "rustls-native-certs", "tokio", "tokio-rustls", + "webpki-roots", ] [[package]] @@ -3255,6 +3533,12 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.3" @@ -3288,9 +3572,9 @@ dependencies = [ [[package]] name = "if-watch" -version = "2.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065c008e570a43c00de6aed9714035e5ea6a498c255323db9091722af6ee67dd" +checksum = "ba7abdbb86e485125dad06c2691e1e393bf3b08c7b743b43aa162a00fd39062e" dependencies = [ "async-io", "core-foundation", @@ -3301,6 +3585,7 @@ dependencies = [ "log", "rtnetlink", "system-configuration", + "tokio", "windows", ] @@ -3322,15 +3607,6 @@ dependencies = [ "rlp", ] -[[package]] -name = "impl-serde" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" -dependencies = [ - "serde", -] - [[package]] name = "impl-serde" version = "0.4.0" @@ -3351,6 +3627,47 @@ dependencies = [ "syn", ] +[[package]] +name = "in-instructions-client" +version = "0.1.0" +dependencies = [ + "async-trait", + "in-instructions-pallet", + "jsonrpsee-core", + "jsonrpsee-http-client", + "parity-scale-codec", + "sp-inherents", +] + +[[package]] +name = "in-instructions-pallet" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "in-instructions-primitives", + "parity-scale-codec", + "scale-info", + "serai-primitives", + "serde", + "sp-inherents", + "sp-runtime", + "sp-std", + "thiserror", + "tokens-pallet", +] + +[[package]] +name = "in-instructions-primitives" +version = "0.1.0" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serai-primitives", + "serde", + "tokens-primitives", +] + [[package]] name = "indenter" version = "0.3.3" @@ -3364,7 +3681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] @@ -3374,190 +3691,12 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" dependencies = [ - "console 0.15.2", + "console 0.15.5", "lazy_static", "number_prefix", "regex", ] -[[package]] -name = "ink_allocator" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c9588a59a0e8997c0b2153cd11b5aaa77c06a0537a6b18f3811d1f1aa098b12" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "ink_engine" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487c3b390b7feb0620496b0cd38683433c7d7e6946b1caabda51e1f23eb24b30" -dependencies = [ - "blake2", - "derive_more", - "parity-scale-codec", - "rand 0.8.5", - "secp256k1", - "sha2 0.10.6", - "sha3", -] - -[[package]] -name = "ink_env" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a891d34301a3dbb1c7b7424c49ae184282b163491c54f9acd17fcbe14a80447b" -dependencies = [ - "arrayref", - "blake2", - "cfg-if", - "derive_more", - "ink_allocator", - "ink_engine", - "ink_metadata", - "ink_prelude", - "ink_primitives", - "num-traits", - "parity-scale-codec", - "paste", - "rand 0.8.5", - "rlibc", - "scale-info", - "secp256k1", - "sha2 0.10.6", - "sha3", - "static_assertions", -] - -[[package]] -name = "ink_lang" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca26e374e0f89c82cf5dabb4309ef3c76a01659ad95186f4e84455c5f4621a0" -dependencies = [ - "derive_more", - "ink_env", - "ink_lang_macro", - "ink_prelude", - "ink_primitives", - "ink_storage", - "parity-scale-codec", -] - -[[package]] -name = "ink_lang_codegen" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fe57826726d89c84fe0b1fafe0dee328f58c8e927be40f0290f04602aacc45c" -dependencies = [ - "blake2", - "derive_more", - "either", - "heck", - "impl-serde 0.3.2", - "ink_lang_ir", - "itertools", - "parity-scale-codec", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "ink_lang_ir" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47d16b2a5340df90f11b2ec2242b37907f5c8396dbbc72c52ec9f2b1a8c90c8" -dependencies = [ - "blake2", - "either", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "ink_lang_macro" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b858be42ac6cde2c15ce6d7fa75cef59b64a3baf37f7105f39208f2b84dadb" -dependencies = [ - "ink_lang_codegen", - "ink_lang_ir", - "ink_primitives", - "parity-scale-codec", - "proc-macro2", - "syn", -] - -[[package]] -name = "ink_metadata" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74913aaed5751f5615af4631b7559328b8ed56c9cb821b89e14af0706176e849" -dependencies = [ - "derive_more", - "impl-serde 0.3.2", - "ink_prelude", - "ink_primitives", - "scale-info", - "serde", -] - -[[package]] -name = "ink_prelude" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f031e6b8495594a7288b089bf4122e76c26b994959d1b2b693bdfe846b14c0e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "ink_primitives" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12cf42dce81d060401c7cec95a392ad6d3c2f18661fa3083f619ce135133c33" -dependencies = [ - "cfg-if", - "ink_prelude", - "parity-scale-codec", - "scale-info", -] - -[[package]] -name = "ink_storage" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c0a98b6acbd79eedf44720412437d713e7195d1407822604de5885b0ee6c7e1" -dependencies = [ - "array-init", - "cfg-if", - "derive_more", - "ink_env", - "ink_metadata", - "ink_prelude", - "ink_primitives", - "ink_storage_derive", - "parity-scale-codec", - "scale-info", -] - -[[package]] -name = "ink_storage_derive" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "babf1d8903dc9219ad8e8aa181eddb919d9794aad1da23ccdce770925b7de2ba" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - [[package]] name = "inout" version = "0.1.3" @@ -3589,19 +3728,32 @@ dependencies = [ ] [[package]] -name = "io-lifetimes" -version = "0.7.5" +name = "interceptor" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" +checksum = "1e8a11ae2da61704edada656798b61c94b35ecac2c58eb955156987d5e6be90b" +dependencies = [ + "async-trait", + "bytes", + "log", + "rand 0.8.5", + "rtcp", + "rtp", + "thiserror", + "tokio", + "waitgroup", + "webrtc-srtp", + "webrtc-util", +] [[package]] name = "io-lifetimes" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3" dependencies = [ "libc", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -3624,20 +3776,20 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b0d96e660696543b251e58030cf9787df56da39dab19ad60eae7353040917e" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" [[package]] name = "is-terminal" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" dependencies = [ - "hermit-abi 0.2.6", - "io-lifetimes 1.0.3", - "rustix 0.36.5", - "windows-sys 0.42.0", + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", ] [[package]] @@ -3651,59 +3803,96 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] [[package]] -name = "jsonrpsee" -version = "0.15.1" +name = "jsonrpc-core" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bd0d559d5e679b1ab2f869b486a11182923863b1b3ee8b421763cdd707b783a" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "jsonrpsee" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" +dependencies = [ + "jsonrpsee-client-transport", "jsonrpsee-core", - "jsonrpsee-http-server", + "jsonrpsee-http-client", "jsonrpsee-proc-macros", + "jsonrpsee-server", "jsonrpsee-types", - "jsonrpsee-ws-server", "tracing", ] [[package]] -name = "jsonrpsee-core" -version = "0.15.1" +name = "jsonrpsee-client-transport" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3dc3e9cf2ba50b7b1d7d76a667619f82846caa39e8e8daa8a4962d74acaddca" +checksum = "965de52763f2004bc91ac5bcec504192440f0b568a5d621c59d9dbd6f886c3fb" +dependencies = [ + "futures-util", + "http", + "jsonrpsee-core", + "jsonrpsee-types", + "pin-project", + "rustls-native-certs", + "soketto", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "webpki-roots", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e70b4439a751a5de7dd5ed55eacff78ebf4ffe0fc009cb1ebb11417f5b536b" dependencies = [ "anyhow", "arrayvec 0.7.2", + "async-lock", "async-trait", "beef", "futures-channel", + "futures-timer", "futures-util", "globset", - "http", "hyper", "jsonrpsee-types", - "lazy_static", "parking_lot 0.12.1", "rand 0.8.5", "rustc-hash", @@ -3713,33 +3902,34 @@ dependencies = [ "thiserror", "tokio", "tracing", - "unicase", ] [[package]] -name = "jsonrpsee-http-server" -version = "0.15.1" +name = "jsonrpsee-http-client" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03802f0373a38c2420c70b5144742d800b509e2937edc4afb116434f07120117" +checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" dependencies = [ - "futures-channel", - "futures-util", + "async-trait", "hyper", + "hyper-rustls", "jsonrpsee-core", "jsonrpsee-types", + "rustc-hash", "serde", "serde_json", + "thiserror", "tokio", "tracing", - "tracing-futures", ] [[package]] name = "jsonrpsee-proc-macros" -version = "0.15.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd67957d4280217247588ac86614ead007b301ca2fa9f19c19f880a536f029e3" +checksum = "baa6da1e4199c10d7b1d0a6e5e8bd8e55f351163b6f4b3cbb044672a69bd4c1c" dependencies = [ + "heck 0.4.1", "proc-macro-crate", "proc-macro2", "quote", @@ -3747,10 +3937,32 @@ dependencies = [ ] [[package]] -name = "jsonrpsee-types" -version = "0.15.1" +name = "jsonrpsee-server" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e290bba767401b646812f608c099b922d8142603c9e73a50fb192d3ac86f4a0d" +checksum = "1fb69dad85df79527c019659a992498d03f8495390496da2f07e6c24c2b356fc" +dependencies = [ + "futures-channel", + "futures-util", + "http", + "hyper", + "jsonrpsee-core", + "jsonrpsee-types", + "serde", + "serde_json", + "soketto", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd522fe1ce3702fd94812965d7bb7a3364b1c9aba743944c5a00529aae80f8c" dependencies = [ "anyhow", "beef", @@ -3760,26 +3972,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "jsonrpsee-ws-server" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d488ba74fb369e5ab68926feb75a483458b88e768d44319f37e4ecad283c7325" -dependencies = [ - "futures-channel", - "futures-util", - "http", - "jsonrpsee-core", - "jsonrpsee-types", - "serde_json", - "soketto", - "tokio", - "tokio-stream", - "tokio-util", - "tracing", - "tracing-futures", -] - [[package]] name = "k256" version = "0.11.6" @@ -3816,46 +4008,33 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "kvdb" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585089ceadba0197ffe9af6740ab350b325e3c1f5fccfbc3522e0250c750409b" +checksum = "e7d770dcb02bf6835887c3a979b5107a04ff4bbde97a5f0928d27404a155add9" dependencies = [ - "parity-util-mem", "smallvec", ] [[package]] name = "kvdb-memorydb" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40d109c87bfb7759edd2a49b2649c1afe25af785d930ad6a38479b4dc70dd873" +checksum = "bf7a85fe66f9ff9cd74e169fdd2c94c6e1e74c412c99a73b4df3200b5d3760b2" dependencies = [ "kvdb", - "parity-util-mem", "parking_lot 0.12.1", ] [[package]] name = "kvdb-rocksdb" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c076cc2cdbac89b9910c853a36c957d3862a779f31c2661174222cefb49ee597" +checksum = "2182b8219fee6bd83aacaab7344e840179ae079d5216aa4e249b4d704646a844" dependencies = [ "kvdb", - "log", "num_cpus", - "parity-util-mem", "parking_lot 0.12.1", "regex", "rocksdb", @@ -3908,9 +4087,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.138" +version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" [[package]] name = "libloading" @@ -3936,17 +4115,16 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" [[package]] name = "libp2p" -version = "0.49.0" +version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec878fda12ebec479186b3914ebc48ff180fa4c51847e11a1a68bf65249e02c1" +checksum = "9c7b0104790be871edcf97db9bd2356604984e623a08d825c3f27852290266b8" dependencies = [ "bytes", "futures", "futures-timer", "getrandom 0.2.8", "instant", - "lazy_static", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-dns", "libp2p-identify", "libp2p-kad", @@ -3955,14 +4133,15 @@ dependencies = [ "libp2p-mplex", "libp2p-noise", "libp2p-ping", + "libp2p-quic", "libp2p-request-response", "libp2p-swarm", - "libp2p-swarm-derive", "libp2p-tcp", "libp2p-wasm-ext", + "libp2p-webrtc", "libp2p-websocket", "libp2p-yamux", - "multiaddr", + "multiaddr 0.16.0", "parking_lot 0.12.1", "pin-project", "smallvec", @@ -3970,9 +4149,9 @@ dependencies = [ [[package]] name = "libp2p-core" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799676bb0807c788065e57551c6527d461ad572162b0519d1958946ff9e0539d" +checksum = "b6a8fcd392ff67af6cc3f03b1426c41f7f26b6b9aff2dc632c1c56dd649e571f" dependencies = [ "asn1_der", "bs58", @@ -3982,17 +4161,52 @@ dependencies = [ "futures", "futures-timer", "instant", - "lazy_static", "log", - "multiaddr", - "multihash", + "multiaddr 0.16.0", + "multihash 0.16.3", "multistream-select", + "once_cell", "parking_lot 0.12.1", "pin-project", "prost", "prost-build", "rand 0.8.5", "rw-stream-sink", + "sec1", + "sha2 0.10.6", + "smallvec", + "thiserror", + "unsigned-varint", + "void", + "zeroize", +] + +[[package]] +name = "libp2p-core" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881d9a54e97d97cdaa4125d48269d97ca8c40e5fefec6b85b30440dc60cc551f" +dependencies = [ + "asn1_der", + "bs58", + "ed25519-dalek", + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "log", + "multiaddr 0.17.0", + "multihash 0.17.0", + "multistream-select", + "once_cell", + "parking_lot 0.12.1", + "pin-project", + "prost", + "prost-build", + "rand 0.8.5", + "rw-stream-sink", + "sec1", "sha2 0.10.6", "smallvec", "thiserror", @@ -4003,13 +4217,12 @@ dependencies = [ [[package]] name = "libp2p-dns" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2322c9fb40d99101def6a01612ee30500c89abbbecb6297b3cd252903a4c1720" +checksum = "8e42a271c1b49f789b92f7fc87749fa79ce5c7bdc88cbdfacb818a4bca47fec5" dependencies = [ - "async-std-resolver", "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "parking_lot 0.12.1", "smallvec", @@ -4018,14 +4231,14 @@ dependencies = [ [[package]] name = "libp2p-identify" -version = "0.40.0" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf9a121f699e8719bda2e6e9e9b6ddafc6cff4602471d6481c1067930ccb29b" +checksum = "c052d0026f4817b44869bfb6810f4e1112f43aec8553f2cb38881c524b563abf" dependencies = [ "asynchronous-codec", "futures", "futures-timer", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "lru", @@ -4039,9 +4252,9 @@ dependencies = [ [[package]] name = "libp2p-kad" -version = "0.41.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6721c200e2021f6c3fab8b6cf0272ead8912d871610ee194ebd628cecf428f22" +checksum = "2766dcd2be8c87d5e1f35487deb22d765f49c6ae1251b3633efe3b25698bd3d2" dependencies = [ "arrayvec 0.7.2", "asynchronous-codec", @@ -4051,7 +4264,7 @@ dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "prost", @@ -4067,31 +4280,31 @@ dependencies = [ [[package]] name = "libp2p-mdns" -version = "0.41.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "761704e727f7d68d58d7bc2231eafae5fc1b9814de24290f126df09d4bd37a15" +checksum = "04f378264aade9872d6ccd315c0accc18be3a35d15fc1b9c36e5b6f983b62b5b" dependencies = [ - "async-io", "data-encoding", - "dns-parser", "futures", "if-watch", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "rand 0.8.5", "smallvec", "socket2", + "tokio", + "trust-dns-proto", "void", ] [[package]] name = "libp2p-metrics" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee31b08e78b7b8bfd1c4204a9dd8a87b4fcdf6dafc57eb51701c1c264a81cb9" +checksum = "5ad8a64f29da86005c86a4d2728b8a0719e9b192f4092b609fd8790acb9dec55" dependencies = [ - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-identify", "libp2p-kad", "libp2p-ping", @@ -4101,14 +4314,14 @@ dependencies = [ [[package]] name = "libp2p-mplex" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692664acfd98652de739a8acbb0a0d670f1d67190a49be6b4395e22c37337d89" +checksum = "03805b44107aa013e7cbbfa5627b31c36cbedfdfb00603c0311998882bc4bace" dependencies = [ "asynchronous-codec", "bytes", "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "nohash-hasher", "parking_lot 0.12.1", @@ -4119,36 +4332,37 @@ dependencies = [ [[package]] name = "libp2p-noise" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048155686bd81fe6cb5efdef0c6290f25ad32a0a42e8f4f72625cf6a505a206f" +checksum = "a978cb57efe82e892ec6f348a536bfbd9fee677adbe5689d7a93ad3a9bffbf2e" dependencies = [ "bytes", "curve25519-dalek 3.2.0", "futures", - "lazy_static", - "libp2p-core", + "libp2p-core 0.38.0", "log", + "once_cell", "prost", "prost-build", "rand 0.8.5", "sha2 0.10.6", "snow", "static_assertions", - "x25519-dalek", + "thiserror", + "x25519-dalek 1.1.1", "zeroize", ] [[package]] name = "libp2p-ping" -version = "0.40.1" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7228b9318d34689521349a86eb39a3c3a802c9efc99a0568062ffb80913e3f91" +checksum = "929fcace45a112536e22b3dcfd4db538723ef9c3cb79f672b98be2cc8e25f37f" dependencies = [ "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "rand 0.8.5", @@ -4156,16 +4370,37 @@ dependencies = [ ] [[package]] -name = "libp2p-request-response" -version = "0.22.1" +name = "libp2p-quic" +version = "0.7.0-alpha" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8827af16a017b65311a410bb626205a9ad92ec0473967618425039fa5231adc1" +checksum = "01e7c867e95c8130667b24409d236d37598270e6da69b3baf54213ba31ffca59" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core 0.38.0", + "libp2p-tls", + "log", + "parking_lot 0.12.1", + "quinn-proto", + "rand 0.8.5", + "rustls 0.20.8", + "thiserror", + "tokio", +] + +[[package]] +name = "libp2p-request-response" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3236168796727bfcf4927f766393415361e2c644b08bedb6a6b13d957c9a4884" dependencies = [ "async-trait", "bytes", "futures", "instant", - "libp2p-core", + "libp2p-core 0.38.0", "libp2p-swarm", "log", "rand 0.8.5", @@ -4175,75 +4410,126 @@ dependencies = [ [[package]] name = "libp2p-swarm" -version = "0.40.1" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46d13df7c37807965d82930c0e4b04a659efcb6cca237373b206043db5398ecf" +checksum = "b2a35472fe3276b3855c00f1c032ea8413615e030256429ad5349cdf67c6e1a0" dependencies = [ "either", "fnv", "futures", "futures-timer", "instant", - "libp2p-core", + "libp2p-core 0.38.0", + "libp2p-swarm-derive", "log", "pin-project", "rand 0.8.5", "smallvec", "thiserror", + "tokio", "void", ] [[package]] name = "libp2p-swarm-derive" -version = "0.30.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eddc4497a8b5a506013c40e8189864f9c3a00db2b25671f428ae9007f3ba32" +checksum = "9d527d5827582abd44a6d80c07ff8b50b4ee238a8979e05998474179e79dc400" dependencies = [ - "heck", + "heck 0.4.1", "quote", "syn", ] [[package]] name = "libp2p-tcp" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9839d96761491c6d3e238e70554b856956fca0ab60feb9de2cd08eed4473fa92" +checksum = "b4b257baf6df8f2df39678b86c578961d48cc8b68642a12f0f763f56c8e5858d" dependencies = [ - "async-io", "futures", "futures-timer", "if-watch", "libc", - "libp2p-core", + "libp2p-core 0.38.0", "log", "socket2", + "tokio", +] + +[[package]] +name = "libp2p-tls" +version = "0.1.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9baf6f6292149e124ee737d9a79dbee783f29473fc368c7faad9d157841078a" +dependencies = [ + "futures", + "futures-rustls", + "libp2p-core 0.39.0", + "rcgen 0.10.0", + "ring", + "rustls 0.20.8", + "thiserror", + "webpki 0.22.0", + "x509-parser 0.14.0", + "yasna", ] [[package]] name = "libp2p-wasm-ext" -version = "0.37.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b5b8e7a73e379e47b1b77f8a82c4721e97eca01abcd18e9cd91a23ca6ce97" +checksum = "1bb1a35299860e0d4b3c02a3e74e3b293ad35ae0cee8a056363b0c862d082069" dependencies = [ "futures", "js-sys", - "libp2p-core", + "libp2p-core 0.38.0", "parity-send-wrapper", "wasm-bindgen", "wasm-bindgen-futures", ] [[package]] -name = "libp2p-websocket" -version = "0.39.0" +name = "libp2p-webrtc" +version = "0.4.0-alpha" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3758ae6f89b2531a24b6d9f5776bda6a626b60a57600d7185d43dfa75ca5ecc4" +checksum = "cdb6cd86dd68cba72308ea05de1cebf3ba0ae6e187c40548167955d4e3970f6a" +dependencies = [ + "async-trait", + "asynchronous-codec", + "bytes", + "futures", + "futures-timer", + "hex", + "if-watch", + "libp2p-core 0.38.0", + "libp2p-noise", + "log", + "multihash 0.16.3", + "prost", + "prost-build", + "prost-codec", + "rand 0.8.5", + "rcgen 0.9.3", + "serde", + "stun", + "thiserror", + "tinytemplate", + "tokio", + "tokio-util", + "webrtc", +] + +[[package]] +name = "libp2p-websocket" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d705506030d5c0aaf2882437c70dab437605f21c5f9811978f694e6917a3b54" dependencies = [ "either", "futures", "futures-rustls", - "libp2p-core", + "libp2p-core 0.38.0", "log", "parking_lot 0.12.1", "quicksink", @@ -4255,12 +4541,12 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.41.1" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6874d66543c4f7e26e3b8ca9a6bead351563a13ab4fafd43c7927f7c0d6c12" +checksum = "4f63594a0aa818642d9d4915c791945053877253f08a3626f13416b5cd928a29" dependencies = [ "futures", - "libp2p-core", + "libp2p-core 0.38.0", "log", "parking_lot 0.12.1", "thiserror", @@ -4269,9 +4555,9 @@ dependencies = [ [[package]] name = "librocksdb-sys" -version = "0.8.0+7.4.4" +version = "0.8.3+7.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611804e4666a25136fcc5f8cf425ab4d26c7f74ea245ffe92ea23b85b6420b5d" +checksum = "557b255ff04123fcc176162f56ed0c9cd42d8f357cf55b3fabeb60f7413741b3" dependencies = [ "bindgen", "bzip2-sys", @@ -4367,20 +4653,13 @@ dependencies = [ [[package]] name = "linregress" -version = "0.4.4" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c601a85f5ecd1aba625247bca0031585fb1c446461b142878a16f8245ddeb8" +checksum = "475015a7f8f017edb28d2e69813be23500ad4b32cfe3421c4148efc97324ee52" dependencies = [ "nalgebra", - "statrs", ] -[[package]] -name = "linux-raw-sys" -version = "0.0.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" - [[package]] name = "linux-raw-sys" version = "0.1.4" @@ -4404,7 +4683,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", - "value-bag", ] [[package]] @@ -4413,7 +4691,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" dependencies = [ - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -4471,9 +4749,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "matrixmultiply" @@ -4516,14 +4794,14 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" dependencies = [ - "rustix 0.36.5", + "rustix", ] [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -4547,14 +4825,22 @@ dependencies = [ ] [[package]] -name = "memory-db" -version = "0.30.0" +name = "memoffset" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ac11bb793c28fa095b7554466f53b3a60a2cd002afdac01bcf135cbd73a269" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memory-db" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0c7cba9ce19ac7ffd2053ac9f49843bbd3f4318feedfd74e85c19d5fb0ba66" dependencies = [ "hash-db", - "hashbrown", - "parity-util-mem", + "hashbrown 0.12.3", ] [[package]] @@ -4627,14 +4913,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -4686,6 +4972,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "monero" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403883d12972e916dd9754cdb90c25441a9abcf435f8e09c3146de100150eeb0" +dependencies = [ + "base58-monero", + "curve25519-dalek 3.2.0", + "fixed-hash 0.7.0", + "hex", + "hex-literal", + "sealed", + "serde", + "serde-big-array", + "thiserror", + "tiny-keccak", +] + [[package]] name = "monero-epee-bin-serde" version = "1.0.1" @@ -4708,17 +5012,38 @@ dependencies = [ "subtle", ] +[[package]] +name = "monero-rpc" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e016b5ed7dbf76e123516b22f35653a95d8c4b784d2ce2113395863dfd9f482f" +dependencies = [ + "anyhow", + "chrono", + "fixed-hash 0.8.0", + "hex", + "http", + "jsonrpc-core", + "monero", + "reqwest", + "serde", + "serde_json", + "tracing", + "uuid 1.3.0", +] + [[package]] name = "monero-serai" version = "0.1.2-alpha" dependencies = [ "base58-monero", - "blake2", + "crc", "curve25519-dalek 3.2.0", "dalek-ff-group", "digest_auth", "dleq", "flexible-transcript", + "futures", "group", "hex", "hex-literal", @@ -4726,6 +5051,7 @@ dependencies = [ "modular-frost", "monero-epee-bin-serde", "monero-generators", + "monero-rpc", "multiexp", "rand 0.8.5", "rand_chacha 0.3.1", @@ -4743,15 +5069,33 @@ dependencies = [ [[package]] name = "multiaddr" -version = "0.14.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c580bfdd8803cce319b047d239559a22f809094aaea4ac13902a1fdcfcd4261" +checksum = "a4aebdb21e90f81d13ed01dc84123320838e53963c2ca94b60b305d3fa64f31e" dependencies = [ "arrayref", - "bs58", "byteorder", "data-encoding", - "multihash", + "multibase", + "multihash 0.16.3", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", +] + +[[package]] +name = "multiaddr" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b53e0cc5907a5c216ba6584bf74be8ab47d6d6289f72793b2dddbf15dc3bf8c" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "multibase", + "multihash 0.17.0", "percent-encoding", "serde", "static_assertions", @@ -4800,10 +5144,23 @@ dependencies = [ ] [[package]] -name = "multihash-derive" -version = "0.8.0" +name = "multihash" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" +dependencies = [ + "core2", + "digest 0.10.6", + "multihash-derive", + "sha2 0.10.6", + "unsigned-varint", +] + +[[package]] +name = "multihash-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -4835,9 +5192,9 @@ dependencies = [ [[package]] name = "nalgebra" -version = "0.27.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462fffe4002f4f2e1f6a9dcf12cc1a6fc0e15989014efc02a941d3e0f5dc2120" +checksum = "d68d47bba83f9e2006d117a9a33af1524e655516b8919caac694427a6fb1e511" dependencies = [ "approx", "matrixmultiply", @@ -4845,17 +5202,15 @@ dependencies = [ "num-complex", "num-rational", "num-traits", - "rand 0.8.5", - "rand_distr", "simba", "typenum", ] [[package]] name = "nalgebra-macros" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01fcc0b8149b4632adc89ac3b7b31a12fb6099a0317a4eb2ebff574ef7de7218" +checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" dependencies = [ "proc-macro2", "quote", @@ -4917,9 +5272,9 @@ dependencies = [ [[package]] name = "netlink-packet-utils" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25af9cf0dc55498b7bd94a1508af7a78706aa0ab715a73c5169273e03c84845e" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" dependencies = [ "anyhow", "byteorder", @@ -4944,15 +5299,15 @@ dependencies = [ [[package]] name = "netlink-sys" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027" +checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" dependencies = [ - "async-io", "bytes", "futures", "libc", "log", + "tokio", ] [[package]] @@ -4970,6 +5325,21 @@ dependencies = [ "bitflags", "cfg-if", "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", + "static_assertions", ] [[package]] @@ -4980,9 +5350,9 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "nom" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", @@ -5007,9 +5377,9 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" dependencies = [ "num-traits", ] @@ -5079,25 +5449,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "crc32fast", - "hashbrown", + "hashbrown 0.12.3", "indexmap", "memchr", ] [[package]] name = "object" -version = "0.30.0" +version = "0.30.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" dependencies = [ "memchr", ] [[package]] -name = "once_cell" -version = "1.16.0" +name = "oid-registry" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "38e20717fa0541f39bd146692035c37bedfa532b3e5071b35761082407546b2a" +dependencies = [ + "asn1-rs 0.3.1", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs 0.5.2", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "opaque-debug" @@ -5209,10 +5597,25 @@ dependencies = [ "libm 0.1.4", ] +[[package]] +name = "pallet-assets" +version = "4.0.0-dev" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std", +] + [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "frame-benchmarking", "frame-support", @@ -5224,74 +5627,10 @@ dependencies = [ "sp-std", ] -[[package]] -name = "pallet-contracts" -version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" -dependencies = [ - "bitflags", - "frame-benchmarking", - "frame-support", - "frame-system", - "impl-trait-for-tuples", - "log", - "pallet-contracts-primitives", - "pallet-contracts-proc-macro", - "parity-scale-codec", - "rand 0.8.5", - "scale-info", - "serde", - "smallvec", - "sp-api", - "sp-core", - "sp-io", - "sp-runtime", - "sp-sandbox", - "sp-std", - "wasm-instrument", - "wasmi-validation", -] - -[[package]] -name = "pallet-contracts-primitives" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" -dependencies = [ - "bitflags", - "parity-scale-codec", - "sp-runtime", - "sp-std", - "sp-weights", -] - -[[package]] -name = "pallet-contracts-proc-macro" -version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pallet-randomness-collective-flip" -version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" -dependencies = [ - "frame-support", - "frame-system", - "parity-scale-codec", - "safe-mix", - "scale-info", - "sp-runtime", - "sp-std", -] - [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "frame-support", "frame-system", @@ -5325,7 +5664,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "frame-benchmarking", "frame-support", @@ -5343,7 +5682,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "frame-support", "frame-system", @@ -5359,7 +5698,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -5375,7 +5714,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -5386,9 +5725,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a7511a0bec4a336b5929999d02b560d2439c993cccf98c26481484e811adc43" +checksum = "df89dd8311063c54ae4e03d9aeb597b04212a57e82c339344130a9cad9b3e2d9" dependencies = [ "blake2", "crc32fast", @@ -5400,14 +5739,15 @@ dependencies = [ "memmap2", "parking_lot 0.12.1", "rand 0.8.5", + "siphasher", "snap", ] [[package]] name = "parity-scale-codec" -version = "3.2.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "366e44391a8af4cfd6002ef6ba072bae071a96aafca98d7d448a34c5dca38b6a" +checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" dependencies = [ "arrayvec 0.7.2", "bitvec 1.0.1", @@ -5420,9 +5760,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9299338969a3d2f491d65f140b00ddec470858402f888af98e8642fb5e8965cd" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -5436,33 +5776,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" -[[package]] -name = "parity-util-mem" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d32c34f4f5ca7f9196001c0aba5a1f9a5a12382c8944b8b0f90233282d1e8f8" -dependencies = [ - "cfg-if", - "hashbrown", - "impl-trait-for-tuples", - "parity-util-mem-derive", - "parking_lot 0.12.1", - "primitive-types", - "smallvec", - "winapi", -] - -[[package]] -name = "parity-util-mem-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" -dependencies = [ - "proc-macro2", - "syn", - "synstructure", -] - [[package]] name = "parity-wasm" version = "0.45.0" @@ -5493,7 +5806,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.5", + "parking_lot_core 0.9.7", ] [[package]] @@ -5512,15 +5825,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.5" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -5536,9 +5849,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "path-slash" @@ -5546,15 +5859,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" -[[package]] -name = "pbkdf2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" -dependencies = [ - "crypto-mac 0.8.0", -] - [[package]] name = "pbkdf2" version = "0.8.0" @@ -5582,6 +5886,24 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -5590,9 +5912,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pest" -version = "2.5.1" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0" +checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7" dependencies = [ "thiserror", "ucd-trie", @@ -5600,9 +5922,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.5.1" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344" +checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7" dependencies = [ "pest", "pest_generator", @@ -5610,9 +5932,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.5.1" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c" +checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" dependencies = [ "pest", "pest_meta", @@ -5623,20 +5945,20 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.5.1" +version = "2.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20" +checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80" dependencies = [ "once_cell", "pest", - "sha1", + "sha2 0.10.6", ] [[package]] name = "petgraph" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", "indexmap", @@ -5649,7 +5971,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ "futures", - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -5770,16 +6092,18 @@ checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" [[package]] name = "polling" -version = "2.5.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" +checksum = "7e1f879b2998099c2d69ab9605d145d5b661195627eccc680002c4918a7fb6fa" dependencies = [ "autocfg", + "bitflags", "cfg-if", + "concurrent-queue", "libc", "log", - "wepoll-ffi", - "windows-sys 0.42.0", + "pin-project-lite 0.2.9", + "windows-sys 0.45.0", ] [[package]] @@ -5790,7 +6114,7 @@ checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" dependencies = [ "cpufeatures", "opaque-debug 0.3.0", - "universal-hash", + "universal-hash 0.4.1", ] [[package]] @@ -5802,7 +6126,19 @@ dependencies = [ "cfg-if", "cpufeatures", "opaque-debug 0.3.0", - "universal-hash", + "universal-hash 0.4.1", +] + +[[package]] +name = "polyval" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash 0.5.0", ] [[package]] @@ -5819,9 +6155,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" -version = "2.1.4" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54fc5dc63ed3bbf19494623db4f3af16842c0d975818e469022d09e53f0aa05" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" dependencies = [ "difflib", "float-cmp", @@ -5849,9 +6185,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8992a85d8e93a28bdf76137db888d3874e3b230dee5ed8bebac4c9f7617773" +checksum = "4ebcd279d20a4a0a2404a33056388e950504d891c855c7975b9a8fef75f3bf04" dependencies = [ "proc-macro2", "syn", @@ -5872,21 +6208,20 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" dependencies = [ - "fixed-hash", + "fixed-hash 0.8.0", "impl-codec", "impl-rlp", - "impl-serde 0.4.0", + "impl-serde", "scale-info", "uint", ] [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ - "once_cell", "thiserror", "toml", ] @@ -5923,9 +6258,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" dependencies = [ "unicode-ident", ] @@ -5969,9 +6304,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c01db6702aa05baa3f57dec92b8eeeeb4cb19e894e73996b32a4093289e54592" +checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" dependencies = [ "bytes", "prost-derive", @@ -5979,12 +6314,12 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5320c680de74ba083512704acb90fe00f28f79207286a848e730c45dd73ed6" +checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" dependencies = [ "bytes", - "heck", + "heck 0.4.1", "itertools", "lazy_static", "log", @@ -6001,9 +6336,9 @@ dependencies = [ [[package]] name = "prost-codec" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011ae9ff8359df7915f97302d591cdd9e0e27fbd5a4ddc5bd13b71079bb20987" +checksum = "0dc34979ff898b6e141106178981ce2596c387ea6e62533facfc61a37fc879c0" dependencies = [ "asynchronous-codec", "bytes", @@ -6014,9 +6349,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8842bad1a5419bca14eac663ba798f6bc19c413c2fdceb5f3ba3b0932d96720" +checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" dependencies = [ "anyhow", "itertools", @@ -6027,11 +6362,10 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017f79637768cde62820bc2d4fe0e45daaa027755c323ad077767c6c5f173091" +checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" dependencies = [ - "bytes", "prost", ] @@ -6061,6 +6395,24 @@ dependencies = [ "pin-project-lite 0.1.12", ] +[[package]] +name = "quinn-proto" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4ced82a24bb281af338b9e8f94429b6eca01b4e66d899f40031f074e74c9" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls 0.20.8", + "slab", + "thiserror", + "tinyvec", + "tracing", + "webpki 0.22.0", +] + [[package]] name = "quote" version = "1.0.23" @@ -6093,7 +6445,6 @@ dependencies = [ "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", - "rand_pcg 0.2.1", ] [[package]] @@ -6164,15 +6515,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "rand_pcg" version = "0.3.1" @@ -6190,9 +6532,9 @@ checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] name = "rayon" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ "either", "rayon-core", @@ -6200,9 +6542,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -6210,6 +6552,31 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rcgen" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" +dependencies = [ + "pem", + "ring", + "time 0.3.20", + "x509-parser 0.13.2", + "yasna", +] + +[[package]] +name = "rcgen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +dependencies = [ + "pem", + "ring", + "time 0.3.20", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -6232,18 +6599,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c78fb8c9293bcd48ef6fce7b4ca950ceaf21210de6e105a883ee280c0f7b9ed" +checksum = "a9af2cf09ef80e610097515e80095b7f76660a92743c4185aff5406cd5ce3dd5" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9c0c92af03644e4806106281fe2e068ac5bc0ae74a707266d06ea27bccee5f" +checksum = "9c501201393982e275433bc55de7d6ae6f00e7699cd5572c5b57581cd69c881b" dependencies = [ "proc-macro2", "quote", @@ -6252,9 +6619,9 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.3.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43a209257d978ef079f3d446331d0f1794f5e0fc19b306a199983857833a779" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" dependencies = [ "fxhash", "log", @@ -6264,9 +6631,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "aho-corasick", "memchr", @@ -6289,21 +6656,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "region" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" dependencies = [ + "bitflags", + "libc", + "mach", "winapi", ] [[package]] name = "reqwest" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" +checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", "bytes", "encoding_rs", "futures-core", @@ -6322,7 +6692,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite 0.2.9", - "rustls", + "rustls 0.20.8", "rustls-pemfile", "serde", "serde_json", @@ -6330,6 +6700,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", + "tokio-socks", "tower-service", "url", "wasm-bindgen", @@ -6384,12 +6755,6 @@ dependencies = [ "digest 0.10.6", ] -[[package]] -name = "rlibc" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" - [[package]] name = "rlp" version = "0.5.2" @@ -6432,19 +6797,30 @@ dependencies = [ "winapi", ] +[[package]] +name = "rtcp" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1919efd6d4a6a85d13388f9487549bb8e359f17198cc03ffd72f79b553873691" +dependencies = [ + "bytes", + "thiserror", + "webrtc-util", +] + [[package]] name = "rtnetlink" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" dependencies = [ - "async-global-executor", "futures", "log", "netlink-packet-route", "netlink-proto", - "nix", + "nix 0.24.3", "thiserror", + "tokio", ] [[package]] @@ -6457,6 +6833,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "rtp" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a095411ff00eed7b12e4c6a118ba984d113e1079582570d56a5ee723f11f80" +dependencies = [ + "async-trait", + "bytes", + "rand 0.8.5", + "serde", + "thiserror", + "webrtc-util", +] + [[package]] name = "rustc-demangle" version = "0.1.21" @@ -6475,15 +6865,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" @@ -6494,43 +6875,51 @@ dependencies = [ ] [[package]] -name = "rustix" -version = "0.35.13" +name = "rusticata-macros" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" dependencies = [ - "bitflags", - "errno", - "io-lifetimes 0.7.5", - "libc", - "linux-raw-sys 0.0.46", - "windows-sys 0.42.0", + "nom", ] [[package]] name = "rustix" -version = "0.36.5" +version = "0.36.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588" +checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc" dependencies = [ "bitflags", "errno", - "io-lifetimes 1.0.3", + "io-lifetimes", "libc", - "linux-raw-sys 0.1.4", - "windows-sys 0.42.0", + "linux-raw-sys", + "windows-sys 0.45.0", ] [[package]] name = "rustls" -version = "0.20.7" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64 0.13.1", + "log", + "ring", + "sct 0.6.1", + "webpki 0.21.4", +] + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", - "sct", - "webpki", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] @@ -6547,18 +6936,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", ] [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "rw-stream-sink" @@ -6573,17 +6962,17 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] -name = "safe-mix" -version = "1.0.1" +name = "safe_arch" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3d055a2582e6b00ed7a31c1524040aa391092bf636328350813f3a0605215c" +checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" dependencies = [ - "rustc_version 0.2.3", + "bytemuck", ] [[package]] @@ -6592,7 +6981,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" dependencies = [ - "cipher 0.4.3", + "cipher 0.4.4", ] [[package]] @@ -6607,7 +6996,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "log", "sp-core", @@ -6618,7 +7007,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "futures", "futures-timer", @@ -6641,7 +7030,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -6657,11 +7046,9 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "impl-trait-for-tuples", "memmap2", - "parity-scale-codec", "sc-chain-spec-derive", "sc-network-common", "sc-telemetry", @@ -6674,7 +7061,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6685,18 +7072,18 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "array-bytes", "chrono", - "clap 4.0.30", + "clap 4.1.8", "fdlimit", "futures", "libp2p", "log", "names", "parity-scale-codec", - "rand 0.7.3", + "rand 0.8.5", "regex", "rpassword", "sc-client-api", @@ -6725,11 +7112,10 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "fnv", "futures", - "hash-db", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -6746,14 +7132,13 @@ dependencies = [ "sp-runtime", "sp-state-machine", "sp-storage", - "sp-trie", "substrate-prometheus-endpoint", ] [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "hash-db", "kvdb", @@ -6766,6 +7151,7 @@ dependencies = [ "parking_lot 0.12.1", "sc-client-api", "sc-state-db", + "schnellru", "sp-arithmetic", "sp-blockchain", "sp-core", @@ -6778,13 +7164,14 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "futures", "futures-timer", "libp2p", "log", + "mockall", "parking_lot 0.12.1", "sc-client-api", "sc-utils", @@ -6802,9 +7189,8 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "lazy_static", "lru", "parity-scale-codec", "parking_lot 0.12.1", @@ -6813,7 +7199,6 @@ dependencies = [ "sc-executor-wasmtime", "sp-api", "sp-core", - "sp-core-hashing-proc-macro", "sp-externalities", "sp-io", "sp-panic-handler", @@ -6828,13 +7213,10 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "environmental", - "parity-scale-codec", "sc-allocator", "sp-maybe-compressed-blob", - "sp-sandbox", "sp-wasm-interface", "thiserror", "wasm-instrument", @@ -6844,14 +7226,12 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "log", - "parity-scale-codec", "sc-allocator", "sc-executor-common", "sp-runtime-interface", - "sp-sandbox", "sp-wasm-interface", "wasmi", ] @@ -6859,19 +7239,17 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ + "anyhow", "cfg-if", "libc", "log", "once_cell", - "parity-scale-codec", - "parity-wasm", - "rustix 0.35.13", + "rustix", "sc-allocator", "sc-executor-common", "sp-runtime-interface", - "sp-sandbox", "sp-wasm-interface", "wasmtime", ] @@ -6879,16 +7257,14 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "ansi_term", "futures", "futures-timer", "log", - "parity-util-mem", "sc-client-api", "sc-network-common", - "sc-transaction-pool-api", "sp-blockchain", "sp-runtime", ] @@ -6896,7 +7272,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "array-bytes", "async-trait", @@ -6911,30 +7287,26 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "array-bytes", "async-trait", "asynchronous-codec", - "bitflags", + "backtrace", "bytes", - "cid", "either", "fnv", - "fork-tree", "futures", "futures-timer", "ip_network", "libp2p", - "linked-hash-map", - "linked_hash_set", "log", "lru", + "mockall", "parity-scale-codec", "parking_lot 0.12.1", "pin-project", - "prost", - "rand 0.7.3", + "rand 0.8.5", "sc-block-builder", "sc-client-api", "sc-consensus", @@ -6958,7 +7330,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "cid", "futures", @@ -6972,13 +7344,12 @@ dependencies = [ "sp-runtime", "thiserror", "unsigned-varint", - "void", ] [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "bitflags", @@ -7004,9 +7375,9 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "ahash", + "ahash 0.8.3", "futures", "futures-timer", "libp2p", @@ -7022,7 +7393,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "array-bytes", "futures", @@ -7043,9 +7414,10 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "array-bytes", + "async-trait", "fork-tree", "futures", "libp2p", @@ -7067,23 +7439,24 @@ dependencies = [ "sp-core", "sp-finality-grandpa", "sp-runtime", + "substrate-prometheus-endpoint", "thiserror", ] [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "array-bytes", "futures", - "hex", "libp2p", "log", "parity-scale-codec", "pin-project", "sc-network-common", "sc-peerset", + "sc-utils", "sp-consensus", "sp-runtime", "substrate-prometheus-endpoint", @@ -7092,7 +7465,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "array-bytes", "bytes", @@ -7106,7 +7479,7 @@ dependencies = [ "once_cell", "parity-scale-codec", "parking_lot 0.12.1", - "rand 0.7.3", + "rand 0.8.5", "sc-client-api", "sc-network-common", "sc-peerset", @@ -7122,7 +7495,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "futures", "libp2p", @@ -7135,7 +7508,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -7144,10 +7517,9 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "futures", - "hash-db", "jsonrpsee", "log", "parity-scale-codec", @@ -7169,18 +7541,16 @@ dependencies = [ "sp-runtime", "sp-session", "sp-version", + "tokio", ] [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "futures", "jsonrpsee", - "log", "parity-scale-codec", - "parking_lot 0.12.1", "sc-chain-spec", "sc-transaction-pool-api", "scale-info", @@ -7189,7 +7559,6 @@ dependencies = [ "sp-core", "sp-rpc", "sp-runtime", - "sp-tracing", "sp-version", "thiserror", ] @@ -7197,53 +7566,60 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "futures", + "http", "jsonrpsee", "log", "serde_json", "substrate-prometheus-endpoint", "tokio", + "tower", + "tower-http", ] [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ + "array-bytes", "futures", + "futures-util", "hex", "jsonrpsee", + "log", "parity-scale-codec", + "parking_lot 0.12.1", "sc-chain-spec", + "sc-client-api", "sc-transaction-pool-api", "serde", "sp-api", "sp-blockchain", "sp-core", "sp-runtime", + "sp-version", "thiserror", + "tokio-stream", ] [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "directories", "exit-future", "futures", "futures-timer", - "hash-db", "jsonrpsee", "log", "parity-scale-codec", - "parity-util-mem", "parking_lot 0.12.1", "pin-project", - "rand 0.7.3", + "rand 0.8.5", "sc-block-builder", "sc-chain-spec", "sc-client-api", @@ -7262,6 +7638,7 @@ dependencies = [ "sc-rpc", "sc-rpc-server", "sc-rpc-spec-v2", + "sc-storage-monitor", "sc-sysinfo", "sc-telemetry", "sc-tracing", @@ -7271,19 +7648,15 @@ dependencies = [ "serde", "serde_json", "sp-api", - "sp-application-crypto", - "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-core", "sp-externalities", - "sp-inherents", "sp-keystore", "sp-runtime", "sp-session", "sp-state-machine", "sp-storage", - "sp-tracing", "sp-transaction-pool", "sp-transaction-storage-proof", "sp-trie", @@ -7300,27 +7673,40 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "log", "parity-scale-codec", - "parity-util-mem", - "parity-util-mem-derive", "parking_lot 0.12.1", - "sc-client-api", "sp-core", ] +[[package]] +name = "sc-storage-monitor" +version = "0.1.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" +dependencies = [ + "clap 4.1.8", + "futures", + "log", + "nix 0.26.2", + "sc-client-db", + "sc-utils", + "sp-core", + "thiserror", + "tokio", +] + [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "futures", "libc", "log", - "rand 0.7.3", - "rand_pcg 0.2.1", + "rand 0.8.5", + "rand_pcg", "regex", "sc-telemetry", "serde", @@ -7333,7 +7719,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "chrono", "futures", @@ -7341,7 +7727,8 @@ dependencies = [ "log", "parking_lot 0.12.1", "pin-project", - "rand 0.7.3", + "rand 0.8.5", + "sc-utils", "serde", "serde_json", "thiserror", @@ -7359,12 +7746,10 @@ dependencies = [ "sc-block-builder", "sc-client-api", "sc-consensus", - "sc-executor", "sc-network", "sc-network-common", "sc-network-gossip", "sc-service", - "sc-transaction-pool", "sp-api", "sp-application-crypto", "sp-blockchain", @@ -7383,7 +7768,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "ansi_term", "atty", @@ -7414,7 +7799,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -7425,15 +7810,15 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "futures", "futures-timer", "linked-hash-map", "log", + "num-traits", "parity-scale-codec", - "parity-util-mem", "parking_lot 0.12.1", "sc-client-api", "sc-transaction-pool-api", @@ -7452,7 +7837,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "futures", @@ -7466,8 +7851,9 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ + "backtrace", "futures", "futures-timer", "lazy_static", @@ -7476,6 +7862,29 @@ dependencies = [ "prometheus", ] +[[package]] +name = "scale-bits" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd7aca73785181cc41f0bbe017263e682b585ca660540ba569133901d013ecf" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "scale-decode" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d823d4be477fc33321f93d08fb6c2698273d044f01362dc27573a750deb7c233" +dependencies = [ + "parity-scale-codec", + "scale-bits", + "scale-info", + "thiserror", +] + [[package]] name = "scale-info" version = "2.3.1" @@ -7503,13 +7912,40 @@ dependencies = [ ] [[package]] -name = "schannel" -version = "0.1.20" +name = "scale-value" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +checksum = "16a5e7810815bd295da73e4216d1dfbced3c7c7c7054d70fa5f6e4c58123fff4" dependencies = [ - "lazy_static", - "windows-sys 0.36.1", + "either", + "frame-metadata", + "parity-scale-codec", + "scale-bits", + "scale-decode", + "scale-info", + "serde", + "thiserror", + "yap", +] + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "schnellru" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +dependencies = [ + "ahash 0.8.3", + "cfg-if", + "hashbrown 0.13.2", ] [[package]] @@ -7552,9 +7988,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scratch" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" [[package]] name = "scrypt" @@ -7568,6 +8004,16 @@ dependencies = [ "sha2 0.10.6", ] +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "sct" version = "0.7.0" @@ -7578,6 +8024,30 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sdp" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d22a5ef407871893fd72b4562ee15e4742269b173959db4b8df6f538c414e13" +dependencies = [ + "rand 0.8.5", + "substring", + "thiserror", + "url", +] + +[[package]] +name = "sealed" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b5e421024b5e5edfbaa8e60ecf90bda9dbffc602dbb230e6028763f85f0c68c" +dependencies = [ + "heck 0.3.3", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sec1" version = "0.3.0" @@ -7594,11 +8064,14 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9512ffd81e3a3503ed401f79c33168b9148c75038956039166cd750eaa037c3" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" dependencies = [ + "bitcoin_hashes", + "rand 0.8.5", "secp256k1-sys", + "serde", ] [[package]] @@ -7621,9 +8094,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.7.0" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ "bitflags", "core-foundation", @@ -7634,9 +8107,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.6.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" dependencies = [ "core-foundation-sys", "libc", @@ -7651,15 +8124,6 @@ dependencies = [ "semver-parser", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.16" @@ -7677,32 +8141,26 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "send_wrapper" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] -name = "serai-extension" +name = "serai-client" version = "0.1.0" dependencies = [ - "ink_env", - "ink_lang", - "parity-scale-codec", -] - -[[package]] -name = "serai-multisig" -version = "0.1.0" -dependencies = [ - "ink_env", - "ink_lang", - "ink_metadata", - "ink_primitives", - "ink_storage", + "jsonrpsee-server", "lazy_static", "parity-scale-codec", + "rand_core 0.6.4", "scale-info", - "serai-extension", + "scale-value", + "serai-primitives", + "serai-runtime", + "sp-core", + "subxt", + "thiserror", + "tokio", ] [[package]] @@ -7710,14 +8168,11 @@ name = "serai-node" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.0.30", + "clap 4.1.8", "frame-benchmarking", "frame-benchmarking-cli", - "frame-system", + "in-instructions-client", "jsonrpsee", - "log", - "pallet-tendermint", - "pallet-transaction-payment", "pallet-transaction-payment-rpc", "sc-basic-authorship", "sc-cli", @@ -7725,9 +8180,7 @@ dependencies = [ "sc-client-db", "sc-consensus", "sc-executor", - "sc-keystore", "sc-network", - "sc-rpc", "sc-rpc-api", "sc-service", "sc-telemetry", @@ -7736,35 +8189,46 @@ dependencies = [ "sc-transaction-pool-api", "serai-runtime", "sp-api", - "sp-application-crypto", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-core", "sp-inherents", "sp-keyring", - "sp-keystore", "sp-runtime", - "sp-tendermint", - "sp-timestamp", "substrate-build-script-utils", "substrate-frame-rpc-system", ] +[[package]] +name = "serai-primitives" +version = "0.1.0" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-runtime", +] + [[package]] name = "serai-processor" version = "0.1.0" dependencies = [ "async-trait", + "bitcoin", + "bitcoin-serai", "curve25519-dalek 3.2.0", "dalek-ff-group", "flexible-transcript", "futures", "group", "hex", + "k256", "modular-frost", "monero-serai", "rand_core 0.6.4", + "secp256k1", "serde", "serde_json", "thiserror", @@ -7782,19 +8246,17 @@ dependencies = [ "frame-system", "frame-system-rpc-runtime-api", "hex-literal", + "in-instructions-pallet", + "pallet-assets", "pallet-balances", - "pallet-contracts", - "pallet-contracts-primitives", - "pallet-randomness-collective-flip", "pallet-session", "pallet-tendermint", - "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "scale-info", + "serai-primitives", "sp-api", - "sp-application-crypto", "sp-block-builder", "sp-core", "sp-inherents", @@ -7806,13 +8268,15 @@ dependencies = [ "sp-transaction-pool", "sp-version", "substrate-wasm-builder", + "tokens-pallet", + "validator-sets-pallet", ] [[package]] name = "serde" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" +checksum = "8cdd151213925e7f1ab45a9bbfb129316bd00799784b174b7cc7bcd16961c49e" dependencies = [ "serde_derive", ] @@ -7828,10 +8292,19 @@ dependencies = [ ] [[package]] -name = "serde_derive" -version = "1.0.151" +name = "serde-big-array" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" +checksum = "3323f09a748af288c3dc2474ea6803ee81f118321775bffa3ac8f7e65c5e90e7" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc80d722935453bcafdc2c9a73cd6fac4dc1938f0346035d84bf99fa9e33217" dependencies = [ "proc-macro2", "quote", @@ -7840,24 +8313,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" dependencies = [ "itoa", "ryu", "serde", ] -[[package]] -name = "serde_nanos" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e44969a61f5d316be20a42ff97816efb3b407a924d06824c3d8a49fa8450de0e" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -7955,21 +8419,11 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" -[[package]] -name = "signal-hook" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] @@ -7996,14 +8450,15 @@ dependencies = [ [[package]] name = "simba" -version = "0.5.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e82063457853d00243beda9952e910b82593e4b07ae9f721b9278a99a0d3d5c" +checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4" dependencies = [ "approx", "num-complex", "num-traits", "paste", + "wide", ] [[package]] @@ -8014,9 +8469,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -8041,26 +8496,26 @@ checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" [[package]] name = "snow" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" +checksum = "12ba5f4d4ff12bdb6a169ed51b7c48c0e0ac4b0b4b31012b2571e97d78d3201d" dependencies = [ - "aes-gcm", + "aes-gcm 0.9.4", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-pre.5", + "curve25519-dalek 4.0.0-rc.0", "rand_core 0.6.4", "ring", - "rustc_version 0.4.0", + "rustc_version", "sha2 0.10.6", "subtle", ] [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -8076,6 +8531,7 @@ dependencies = [ "bytes", "flate2", "futures", + "http", "httparse", "log", "rand 0.8.5", @@ -8098,7 +8554,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "hash-db", "log", @@ -8116,7 +8572,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "blake2", "proc-macro-crate", @@ -8127,8 +8583,8 @@ dependencies = [ [[package]] name = "sp-application-crypto" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "7.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "parity-scale-codec", "scale-info", @@ -8140,15 +8596,14 @@ dependencies = [ [[package]] name = "sp-arithmetic" -version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "6.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "integer-sqrt", "num-traits", "parity-scale-codec", "scale-info", "serde", - "sp-debug-derive", "sp-std", "static_assertions", ] @@ -8156,7 +8611,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "parity-scale-codec", "sp-api", @@ -8168,7 +8623,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "futures", "log", @@ -8186,11 +8641,10 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "futures", - "futures-timer", "log", "parity-scale-codec", "sp-core", @@ -8204,29 +8658,28 @@ dependencies = [ [[package]] name = "sp-core" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "7.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "array-bytes", "base58 0.2.0", "bitflags", "blake2", - "byteorder", + "bounded-collections", "dyn-clonable", "ed25519-zebra", "futures", "hash-db", "hash256-std-hasher", - "impl-serde 0.4.0", + "impl-serde", "lazy_static", "libsecp256k1", "log", "merlin 2.0.1", - "num-traits", "parity-scale-codec", "parking_lot 0.12.1", "primitive-types", - "rand 0.7.3", + "rand 0.8.5", "regex", "scale-info", "schnorrkel", @@ -8243,14 +8696,13 @@ dependencies = [ "substrate-bip39", "thiserror", "tiny-bip39", - "wasmi", "zeroize", ] [[package]] name = "sp-core-hashing" -version = "4.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "5.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "blake2", "byteorder", @@ -8264,7 +8716,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "proc-macro2", "quote", @@ -8275,7 +8727,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -8283,8 +8735,8 @@ dependencies = [ [[package]] name = "sp-debug-derive" -version = "4.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "5.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "proc-macro2", "quote", @@ -8293,8 +8745,8 @@ dependencies = [ [[package]] name = "sp-externalities" -version = "0.12.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "0.13.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "environmental", "parity-scale-codec", @@ -8305,7 +8757,7 @@ dependencies = [ [[package]] name = "sp-finality-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "finality-grandpa", "log", @@ -8323,11 +8775,12 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "impl-trait-for-tuples", "parity-scale-codec", + "scale-info", "sp-core", "sp-runtime", "sp-std", @@ -8336,16 +8789,16 @@ dependencies = [ [[package]] name = "sp-io" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "7.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "bytes", + "ed25519", + "ed25519-dalek", "futures", - "hash-db", "libsecp256k1", "log", "parity-scale-codec", - "parking_lot 0.12.1", "secp256k1", "sp-core", "sp-externalities", @@ -8355,15 +8808,14 @@ dependencies = [ "sp-std", "sp-tracing", "sp-trie", - "sp-wasm-interface", "tracing", "tracing-core", ] [[package]] name = "sp-keyring" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "7.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "lazy_static", "sp-core", @@ -8373,8 +8825,8 @@ dependencies = [ [[package]] name = "sp-keystore" -version = "0.12.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "0.13.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "futures", @@ -8391,7 +8843,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "thiserror", "zstd", @@ -8400,7 +8852,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "sp-api", "sp-core", @@ -8409,8 +8861,8 @@ dependencies = [ [[package]] name = "sp-panic-handler" -version = "4.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "5.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "backtrace", "lazy_static", @@ -8420,7 +8872,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "rustc-hash", "serde", @@ -8429,17 +8881,16 @@ dependencies = [ [[package]] name = "sp-runtime" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "7.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "either", "hash256-std-hasher", "impl-trait-for-tuples", "log", "parity-scale-codec", - "parity-util-mem", "paste", - "rand 0.7.3", + "rand 0.8.5", "scale-info", "serde", "sp-application-crypto", @@ -8452,8 +8903,8 @@ dependencies = [ [[package]] name = "sp-runtime-interface" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "7.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -8470,8 +8921,8 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" -version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "6.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "Inflector", "proc-macro-crate", @@ -8480,24 +8931,10 @@ dependencies = [ "syn", ] -[[package]] -name = "sp-sandbox" -version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" -dependencies = [ - "log", - "parity-scale-codec", - "sp-core", - "sp-io", - "sp-std", - "sp-wasm-interface", - "wasmi", -] - [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "parity-scale-codec", "scale-info", @@ -8511,25 +8948,25 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "parity-scale-codec", "scale-info", + "sp-core", "sp-runtime", "sp-std", ] [[package]] name = "sp-state-machine" -version = "0.12.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "0.13.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "hash-db", "log", - "num-traits", "parity-scale-codec", "parking_lot 0.12.1", - "rand 0.7.3", + "rand 0.8.5", "smallvec", "sp-core", "sp-externalities", @@ -8538,20 +8975,19 @@ dependencies = [ "sp-trie", "thiserror", "tracing", - "trie-root", ] [[package]] name = "sp-std" -version = "4.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "5.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" [[package]] name = "sp-storage" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "7.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "impl-serde 0.4.0", + "impl-serde", "parity-scale-codec", "ref-cast", "serde", @@ -8571,13 +9007,12 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "futures-timer", "log", "parity-scale-codec", - "sp-api", "sp-inherents", "sp-runtime", "sp-std", @@ -8586,8 +9021,8 @@ dependencies = [ [[package]] name = "sp-tracing" -version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "6.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "parity-scale-codec", "sp-std", @@ -8599,7 +9034,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "sp-api", "sp-runtime", @@ -8608,7 +9043,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "async-trait", "log", @@ -8623,19 +9058,19 @@ dependencies = [ [[package]] name = "sp-trie" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "7.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "ahash", + "ahash 0.8.3", "hash-db", - "hashbrown", + "hashbrown 0.12.3", "lazy_static", - "lru", "memory-db", "nohash-hasher", "parity-scale-codec", "parking_lot 0.12.1", "scale-info", + "schnellru", "sp-core", "sp-std", "thiserror", @@ -8647,9 +9082,9 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "impl-serde 0.4.0", + "impl-serde", "parity-scale-codec", "parity-wasm", "scale-info", @@ -8664,7 +9099,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -8674,9 +9109,10 @@ dependencies = [ [[package]] name = "sp-wasm-interface" -version = "6.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +version = "7.0.0" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ + "anyhow", "impl-trait-for-tuples", "log", "parity-scale-codec", @@ -8688,9 +9124,8 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "impl-trait-for-tuples", "parity-scale-codec", "scale-info", "serde", @@ -8719,9 +9154,9 @@ dependencies = [ [[package]] name = "ss58-registry" -version = "1.36.0" +version = "1.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d92659e7d18d82b803824a9ba5a6022cff101c3491d027c1c1d8d30e749284" +checksum = "ecf0bd63593ef78eca595a7fc25e9a443ca46fe69fd472f8f09f5245cdcd769d" dependencies = [ "Inflector", "num-format", @@ -8772,24 +9207,11 @@ dependencies = [ "syn", ] -[[package]] -name = "statrs" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05bdbb8e4e78216a85785a85d3ec3183144f98d0097b9281802c019bb07a6f05" -dependencies = [ - "approx", - "lazy_static", - "nalgebra", - "num-traits", - "rand 0.8.5", -] - [[package]] name = "string_cache" -version = "0.8.4" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", @@ -8819,13 +9241,32 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", "syn", ] +[[package]] +name = "stun" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e94b1ec00bad60e6410e058b52f1c66de3dc5fe4d62d09b3e52bb7d3b73e25" +dependencies = [ + "base64 0.13.1", + "crc", + "lazy_static", + "md-5 0.10.5", + "rand 0.8.5", + "ring", + "subtle", + "thiserror", + "tokio", + "url", + "webrtc-util", +] + [[package]] name = "substrate-bip39" version = "0.4.4" @@ -8842,7 +9283,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "platforms 2.0.0", ] @@ -8850,17 +9291,15 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "frame-system-rpc-runtime-api", "futures", "jsonrpsee", "log", "parity-scale-codec", - "sc-client-api", "sc-rpc-api", "sc-transaction-pool-api", - "serde_json", "sp-api", "sp-block-builder", "sp-blockchain", @@ -8871,9 +9310,8 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ - "futures-util", "hyper", "log", "prometheus", @@ -8884,11 +9322,11 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/serai-dex/substrate#881cfbc59c8b65bcccc9fa6187e5096ac3594e3a" +source = "git+https://github.com/serai-dex/substrate#b1c7248b1fc93e3a453ffa1a14c7bf61dd19f767" dependencies = [ "ansi_term", "build-helper", - "cargo_metadata 0.14.2", + "cargo_metadata", "filetime", "sp-maybe-compressed-blob", "strum", @@ -8898,6 +9336,15 @@ dependencies = [ "wasm-opt", ] +[[package]] +name = "substring" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86" +dependencies = [ + "autocfg", +] + [[package]] name = "subtle" version = "2.4.1" @@ -8905,10 +9352,83 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] -name = "svm-rs" -version = "0.2.18" +name = "subxt" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4cdcf91153dc0e4e0637f26f042ada32a3b552bc8115935c7bf96f80132b0a" +checksum = "e3cbc78fd36035a24883eada29e0205b9b1416172530a7d00a60c07d0337db0c" +dependencies = [ + "bitvec 1.0.1", + "derivative", + "frame-metadata", + "futures", + "getrandom 0.2.8", + "hex", + "jsonrpsee", + "parity-scale-codec", + "parking_lot 0.12.1", + "scale-decode", + "scale-info", + "scale-value", + "serde", + "serde_json", + "sp-core", + "sp-runtime", + "subxt-macro", + "subxt-metadata", + "thiserror", + "tracing", +] + +[[package]] +name = "subxt-codegen" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7722c31febf55eb300c73d977da5d65cfd6fb443419b1185b9abcdd9925fd7be" +dependencies = [ + "darling", + "frame-metadata", + "heck 0.4.1", + "hex", + "jsonrpsee", + "parity-scale-codec", + "proc-macro-error", + "proc-macro2", + "quote", + "scale-info", + "subxt-metadata", + "syn", + "tokio", +] + +[[package]] +name = "subxt-macro" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f64826f2c4ba20e3b2a86ec81a6ae8655ca6b6a4c2a6ccc888b6615efc2df14" +dependencies = [ + "darling", + "proc-macro-error", + "subxt-codegen", + "syn", +] + +[[package]] +name = "subxt-metadata" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869af75e23513538ad0af046af4a97b8d684e8d202e35ff4127ee061c1110813" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-core", +] + +[[package]] +name = "svm-rs" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01afefe60c02f4a2271fb15d1965c37856712cebb338330b06649d12afec42df" dependencies = [ "anyhow", "cfg-if", @@ -8937,9 +9457,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -8987,22 +9507,21 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "target-lexicon" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "tempfile" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" dependencies = [ "cfg-if", "fastrand", - "libc", "redox_syscall", - "remove_dir_all", - "winapi", + "rustix", + "windows-sys 0.42.0", ] [[package]] @@ -9031,9 +9550,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" dependencies = [ "winapi-util", ] @@ -9062,18 +9581,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "a5ab016db510546d856297882807df8da66a16fb8c4101cb8b30054b0d5b2d9c" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "5420d42e90af0c38c3290abcca25b9b3bdf379fc9f55c528f53a269d9c9a267e" dependencies = [ "proc-macro2", "quote", @@ -9088,10 +9607,11 @@ checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -9106,12 +9626,11 @@ dependencies = [ [[package]] name = "tikv-jemalloc-sys" -version = "0.5.2+5.3.0-patched" +version = "0.5.3+5.3.0-patched" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec45c14da997d0925c7835883e4d5c181f196fa142f8c19d7643d1e9af2592c3" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" dependencies = [ "cc", - "fs_extra", "libc", ] @@ -9128,9 +9647,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "itoa", "serde", @@ -9146,26 +9665,26 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" dependencies = [ "time-core", ] [[package]] name = "tiny-bip39" -version = "0.8.2" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" dependencies = [ "anyhow", - "hmac 0.8.1", + "hmac 0.12.1", "once_cell", - "pbkdf2 0.4.0", - "rand 0.7.3", + "pbkdf2 0.11.0", + "rand 0.8.5", "rustc-hash", - "sha2 0.9.9", + "sha2 0.10.6", "thiserror", "unicode-normalization", "wasm-bindgen", @@ -9181,6 +9700,16 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -9192,15 +9721,39 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokens-pallet" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-assets", + "parity-scale-codec", + "scale-info", + "serai-primitives", + "tokens-primitives", +] + +[[package]] +name = "tokens-primitives" +version = "0.1.0" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serai-primitives", + "serde", + "sp-runtime", +] [[package]] name = "tokio" -version = "1.23.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" +checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" dependencies = [ "autocfg", "bytes", @@ -9213,7 +9766,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -9229,9 +9782,9 @@ dependencies = [ [[package]] name = "tokio-native-tls" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", "tokio", @@ -9243,27 +9796,40 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls", + "rustls 0.20.8", + "tokio", + "webpki 0.22.0", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +dependencies = [ + "either", + "futures-util", + "thiserror", "tokio", - "webpki", ] [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" dependencies = [ "futures-core", "pin-project-lite 0.2.9", "tokio", + "tokio-util", ] [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", @@ -9276,13 +9842,48 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite 0.2.9", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -9296,6 +9897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", + "log", "pin-project-lite 0.2.9", "tracing-attributes", "tracing-core", @@ -9378,12 +9980,12 @@ dependencies = [ [[package]] name = "trie-db" -version = "0.24.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "004e1e8f92535694b4cb1444dc5a8073ecf0815e3357f729638b9f8fc4062908" +checksum = "3390c0409daaa6027d6681393316f4ccd3ff82e1590a1e4725014e3ae2bf1920" dependencies = [ "hash-db", - "hashbrown", + "hashbrown 0.13.2", "log", "rustc-hex", "smallvec", @@ -9416,8 +10018,10 @@ dependencies = [ "lazy_static", "rand 0.8.5", "smallvec", + "socket2", "thiserror", "tinyvec", + "tokio", "tracing", "url", ] @@ -9437,15 +10041,16 @@ dependencies = [ "resolv-conf", "smallvec", "thiserror", + "tokio", "tracing", "trust-dns-proto", ] [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tt-call" @@ -9453,6 +10058,25 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" +[[package]] +name = "turn" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4712ee30d123ec7ae26d1e1b218395a16c87cdbaf4b3925d170d684af62ea5e8" +dependencies = [ + "async-trait", + "base64 0.13.1", + "futures", + "log", + "md-5 0.10.5", + "rand 0.8.5", + "ring", + "stun", + "thiserror", + "tokio", + "webrtc-util", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -9489,26 +10113,17 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "524b68aca1d05e03fdf03fcdce2c6c94b6daf6d16861ddaa7e4f2b6638a9052c" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" @@ -9521,9 +10136,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" @@ -9547,6 +10162,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "universal-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "unsigned-varint" version = "0.7.1" @@ -9586,22 +10211,42 @@ dependencies = [ "serde", ] +[[package]] +name = "uuid" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +dependencies = [ + "getrandom 0.2.8", +] + +[[package]] +name = "validator-sets-pallet" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serai-primitives", + "validator-sets-primitives", +] + +[[package]] +name = "validator-sets-primitives" +version = "0.1.0" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", +] + [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "value-bag" -version = "1.0.0-alpha.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" -dependencies = [ - "ctor", - "version_check", -] - [[package]] name = "vcpkg" version = "0.2.15" @@ -9620,6 +10265,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "waitgroup" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1f50000a783467e6c0200f9d10642f4bc424e39efc1b770203e88b488f79292" +dependencies = [ + "atomic-waker", +] + [[package]] name = "waker-fn" version = "1.1.0" @@ -9667,9 +10321,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -9677,9 +10331,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -9692,9 +10346,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" dependencies = [ "cfg-if", "js-sys", @@ -9704,9 +10358,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -9714,9 +10368,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -9727,9 +10381,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "wasm-instrument" @@ -9742,9 +10396,9 @@ dependencies = [ [[package]] name = "wasm-opt" -version = "0.110.2" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b68e8037b4daf711393f4be2056246d12d975651b14d581520ad5d1f19219cec" +checksum = "84a303793cbc01fb96551badfc7367db6007396bba6bac97936b3c8b6f7fdb41" dependencies = [ "anyhow", "libc", @@ -9758,9 +10412,9 @@ dependencies = [ [[package]] name = "wasm-opt-cxx-sys" -version = "0.110.2" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91adbad477e97bba3fbd21dd7bfb594e7ad5ceb9169ab1c93ab9cb0ada636b6f" +checksum = "d9c9deb56f8a9f2ec177b3bd642a8205621835944ed5da55f2388ef216aca5a4" dependencies = [ "anyhow", "cxx", @@ -9770,9 +10424,9 @@ dependencies = [ [[package]] name = "wasm-opt-sys" -version = "0.110.2" +version = "0.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4fa5a322a4e6ac22fd141f498d56afbdbf9df5debeac32380d2dcaa3e06941" +checksum = "4432e28b542738a9776cedf92e8a99d8991c7b4667ee2c7ccddfb479dd2856a7" dependencies = [ "anyhow", "cc", @@ -9827,22 +10481,24 @@ dependencies = [ "memory_units", "num-rational", "num-traits", + "region", ] [[package]] name = "wasmparser" -version = "0.89.1" +version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5d3e08b13876f96dd55608d03cd4883a0545884932d5adf11925876c96daef" +checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4" dependencies = [ "indexmap", + "url", ] [[package]] name = "wasmtime" -version = "1.0.2" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad5af6ba38311282f2a21670d96e78266e8c8e2f38cbcd52c254df6ccbc7731" +checksum = "f6e89f9819523447330ffd70367ef4a18d8c832e24e8150fe054d1d912841632" dependencies = [ "anyhow", "bincode", @@ -9863,23 +10519,23 @@ dependencies = [ "wasmtime-environ", "wasmtime-jit", "wasmtime-runtime", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] name = "wasmtime-asm-macros" -version = "1.0.2" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45de63ddfc8b9223d1adc8f7b2ee5f35d1f6d112833934ad7ea66e4f4339e597" +checksum = "9bd3a5e46c198032da934469f3a6e48649d1f9142438e4fd4617b68a35644b8a" dependencies = [ "cfg-if", ] [[package]] name = "wasmtime-cache" -version = "1.0.2" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcd849399d17d2270141cfe47fa0d91ee52d5f8ea9b98cf7ddde0d53e5f79882" +checksum = "b389ae9b678b9c3851091a4804f4182d688d27aff7abc9aa37fa7be37d8ecffa" dependencies = [ "anyhow", "base64 0.13.1", @@ -9887,19 +10543,19 @@ dependencies = [ "directories-next", "file-per-thread-logger", "log", - "rustix 0.35.13", + "rustix", "serde", - "sha2 0.9.9", + "sha2 0.10.6", "toml", - "windows-sys 0.36.1", + "windows-sys 0.42.0", "zstd", ] [[package]] name = "wasmtime-cranelift" -version = "1.0.2" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd91339b742ff20bfed4532a27b73c86b5bcbfedd6bea2dcdf2d64471e1b5c6" +checksum = "59b2c92a08c0db6efffd88fdc97d7aa9c7c63b03edb0971dbca745469f820e8c" dependencies = [ "anyhow", "cranelift-codegen", @@ -9918,9 +10574,9 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "1.0.2" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebb881c61f4f627b5d45c54e629724974f8a8890d455bcbe634330cc27309644" +checksum = "9a6db9fc52985ba06ca601f2ff0ff1f526c5d724c7ac267b47326304b0c97883" dependencies = [ "anyhow", "cranelift-entity", @@ -9937,9 +10593,9 @@ dependencies = [ [[package]] name = "wasmtime-jit" -version = "1.0.2" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1985c628011fe26adf5e23a5301bdc79b245e0e338f14bb58b39e4e25e4d8681" +checksum = "b77e3a52cd84d0f7f18554afa8060cfe564ccac61e3b0802d3fd4084772fa5f6" dependencies = [ "addr2line 0.17.0", "anyhow", @@ -9950,32 +10606,42 @@ dependencies = [ "log", "object 0.29.0", "rustc-demangle", - "rustix 0.35.13", "serde", "target-lexicon", - "thiserror", "wasmtime-environ", "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", "wasmtime-runtime", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] name = "wasmtime-jit-debug" -version = "1.0.2" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f671b588486f5ccec8c5a3dba6b4c07eac2e66ab8c60e6f4e53717c77f709731" +checksum = "d0245e8a9347017c7185a72e215218a802ff561545c242953c11ba00fccc930f" dependencies = [ "object 0.29.0", "once_cell", - "rustix 0.35.13", + "rustix", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67d412e9340ab1c83867051d8d1d7c90aa8c9afc91da086088068e2734e25064" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.42.0", ] [[package]] name = "wasmtime-runtime" -version = "1.0.2" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8f92ad4b61736339c29361da85769ebc200f184361959d1792832e592a1afd" +checksum = "d594e791b5fdd4dbaf8cf7ae62f2e4ff85018ce90f483ca6f42947688e48827d" dependencies = [ "anyhow", "cc", @@ -9988,19 +10654,18 @@ dependencies = [ "memoffset 0.6.5", "paste", "rand 0.8.5", - "rustix 0.35.13", - "thiserror", + "rustix", "wasmtime-asm-macros", "wasmtime-environ", "wasmtime-jit-debug", - "windows-sys 0.36.1", + "windows-sys 0.42.0", ] [[package]] name = "wasmtime-types" -version = "1.0.2" +version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23d61cb4c46e837b431196dd06abb11731541021916d03476a178b54dc07aeb" +checksum = "a6688d6f96d4dbc1f89fab626c56c1778936d122b5f4ae7a57c2eb42b8d982e2" dependencies = [ "cranelift-entity", "serde", @@ -10010,14 +10675,24 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "webpki" version = "0.22.0" @@ -10034,29 +10709,242 @@ version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ - "webpki", + "webpki 0.22.0", ] [[package]] -name = "wepoll-ffi" -version = "0.1.2" +name = "webrtc" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +checksum = "2d3bc9049bdb2cea52f5fd4f6f728184225bdb867ed0dc2410eab6df5bdd67bb" dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "hex", + "interceptor", + "lazy_static", + "log", + "rand 0.8.5", + "rcgen 0.9.3", + "regex", + "ring", + "rtcp", + "rtp", + "rustls 0.19.1", + "sdp", + "serde", + "serde_json", + "sha2 0.10.6", + "stun", + "thiserror", + "time 0.3.20", + "tokio", + "turn", + "url", + "waitgroup", + "webrtc-data", + "webrtc-dtls", + "webrtc-ice", + "webrtc-mdns", + "webrtc-media", + "webrtc-sctp", + "webrtc-srtp", + "webrtc-util", +] + +[[package]] +name = "webrtc-data" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef36a4d12baa6e842582fe9ec16a57184ba35e1a09308307b67d43ec8883100" +dependencies = [ + "bytes", + "derive_builder", + "log", + "thiserror", + "tokio", + "webrtc-sctp", + "webrtc-util", +] + +[[package]] +name = "webrtc-dtls" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942be5bd85f072c3128396f6e5a9bfb93ca8c1939ded735d177b7bcba9a13d05" +dependencies = [ + "aes 0.6.0", + "aes-gcm 0.10.1", + "async-trait", + "bincode", + "block-modes", + "byteorder", + "ccm", + "curve25519-dalek 3.2.0", + "der-parser 8.2.0", + "elliptic-curve", + "hkdf", + "hmac 0.12.1", + "log", + "oid-registry 0.6.1", + "p256", + "p384", + "rand 0.8.5", + "rand_core 0.6.4", + "rcgen 0.9.3", + "ring", + "rustls 0.19.1", + "sec1", + "serde", + "sha1", + "sha2 0.10.6", + "signature", + "subtle", + "thiserror", + "tokio", + "webpki 0.21.4", + "webrtc-util", + "x25519-dalek 2.0.0-pre.1", + "x509-parser 0.13.2", +] + +[[package]] +name = "webrtc-ice" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465a03cc11e9a7d7b4f9f99870558fe37a102b65b93f8045392fef7c67b39e80" +dependencies = [ + "arc-swap", + "async-trait", + "crc", + "log", + "rand 0.8.5", + "serde", + "serde_json", + "stun", + "thiserror", + "tokio", + "turn", + "url", + "uuid 1.3.0", + "waitgroup", + "webrtc-mdns", + "webrtc-util", +] + +[[package]] +name = "webrtc-mdns" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f08dfd7a6e3987e255c4dbe710dde5d94d0f0574f8a21afa95d171376c143106" +dependencies = [ + "log", + "socket2", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-media" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a3c157a040324e5049bcbd644ffc9079e6738fa2cfab2bcff64e5cc4c00d7" +dependencies = [ + "byteorder", + "bytes", + "derive_builder", + "displaydoc", + "rand 0.8.5", + "rtp", + "thiserror", + "webrtc-util", +] + +[[package]] +name = "webrtc-sctp" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d47adcd9427eb3ede33d5a7f3424038f63c965491beafcc20bc650a2f6679c0" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "crc", + "log", + "rand 0.8.5", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-srtp" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6183edc4c1c6c0175f8812eefdce84dfa0aea9c3ece71c2bf6ddd3c964de3da5" +dependencies = [ + "aead 0.4.3", + "aes 0.7.5", + "aes-gcm 0.9.4", + "async-trait", + "byteorder", + "bytes", + "ctr 0.8.0", + "hmac 0.11.0", + "log", + "rtcp", + "rtp", + "sha-1", + "subtle", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-util" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f1db1727772c05cf7a2cfece52c3aca8045ca1e176cd517d323489aa3c6d87" +dependencies = [ + "async-trait", + "bitflags", + "bytes", "cc", + "ipnet", + "lazy_static", + "libc", + "log", + "nix 0.24.3", + "rand 0.8.5", + "thiserror", + "tokio", + "winapi", ] [[package]] name = "which" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", "once_cell", ] +[[package]] +name = "wide" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b689b6c49d6549434bf944e6b0f39238cf63693cb7a147e9d887507fffa3b223" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "widestring" version = "0.5.1" @@ -10107,19 +10995,6 @@ dependencies = [ "windows_x86_64_msvc 0.34.0", ] -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - [[package]] name = "windows-sys" version = "0.42.0" @@ -10127,19 +11002,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_x86_64_msvc 0.42.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.1", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" @@ -10149,15 +11048,9 @@ checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" [[package]] name = "windows_aarch64_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" @@ -10167,15 +11060,9 @@ checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" [[package]] name = "windows_i686_gnu" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" @@ -10185,15 +11072,9 @@ checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" [[package]] name = "windows_i686_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" @@ -10203,21 +11084,15 @@ checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" [[package]] name = "windows_x86_64_gnu" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" @@ -10227,15 +11102,9 @@ checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" [[package]] name = "windows_x86_64_msvc" -version = "0.36.1" +version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" [[package]] name = "winreg" @@ -10248,15 +11117,16 @@ dependencies = [ [[package]] name = "ws_stream_wasm" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ca1ab42f5afed7fc332b22b6e932ca5414b209465412c8cdf0ad23bc0de645" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" dependencies = [ "async_io_stream", "futures", "js-sys", + "log", "pharos", - "rustc_version 0.4.0", + "rustc_version", "send_wrapper", "thiserror", "wasm-bindgen", @@ -10284,6 +11154,54 @@ dependencies = [ "zeroize", ] +[[package]] +name = "x25519-dalek" +version = "2.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df" +dependencies = [ + "curve25519-dalek 3.2.0", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9bace5b5589ffead1afb76e43e34cff39cd0f3ce7e170ae0c29e53b88eb1c" +dependencies = [ + "asn1-rs 0.3.1", + "base64 0.13.1", + "data-encoding", + "der-parser 7.0.0", + "lazy_static", + "nom", + "oid-registry 0.4.0", + "ring", + "rusticata-macros", + "thiserror", + "time 0.3.20", +] + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs 0.5.2", + "base64 0.13.1", + "data-encoding", + "der-parser 8.2.0", + "lazy_static", + "nom", + "oid-registry 0.6.1", + "rusticata-macros", + "thiserror", + "time 0.3.20", +] + [[package]] name = "yamux" version = "0.10.2" @@ -10304,6 +11222,21 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yap" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc77f52dc9e9b10d55d3f4462c3b7fc393c4f17975d641542833ab2d3bc26ef" + +[[package]] +name = "yasna" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" +dependencies = [ + "time 0.3.20", +] + [[package]] name = "zalloc" version = "0.1.0" @@ -10334,9 +11267,9 @@ dependencies = [ [[package]] name = "zip" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080" +checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef" dependencies = [ "aes 0.7.5", "byteorder", @@ -10348,7 +11281,7 @@ dependencies = [ "hmac 0.12.1", "pbkdf2 0.11.0", "sha1", - "time 0.3.17", + "time 0.3.20", "zstd", ] @@ -10373,10 +11306,11 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.4+zstd.1.5.2" +version = "2.0.7+zstd.1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" +checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" dependencies = [ "cc", "libc", + "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index df9adc65..2d1aea59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,19 @@ members = [ "processor", + "substrate/serai/primitives", + "substrate/serai/client", + + "substrate/tokens/primitives", + "substrate/tokens/pallet", + + "substrate/in-instructions/primitives", + "substrate/in-instructions/pallet", + "substrate/in-instructions/client", + + "substrate/validator-sets/primitives", + "substrate/validator-sets/pallet", + "substrate/tendermint/machine", "substrate/tendermint/primitives", "substrate/tendermint/client", @@ -29,13 +42,10 @@ members = [ "substrate/runtime", "substrate/node", - - "contracts/extension", - "contracts/multisig", ] # Always compile Monero (and a variety of dependencies) with optimizations due -# to the unoptimized performance of Bulletproofs +# to the extensive operations required for Bulletproofs [profile.dev.package] subtle = { opt-level = 3 } curve25519-dalek = { opt-level = 3 } @@ -54,7 +64,7 @@ monero-serai = { opt-level = 3 } [profile.release] panic = "unwind" +# Required for subxt [patch.crates-io] -# array-bytes 4.1.0 is GPL-3.0. -# array-bytes git, which has no code changes, includes a dual-license under Apache-2.0. -array-bytes = { git = "https://github.com/hack-ink/array-bytes", rev = "994cd29b66bd2ab5c8c15f0b15a1618d4bb2d94c" } +sp-core = { git = "https://github.com/serai-dex/substrate" } +sp-runtime = { git = "https://github.com/serai-dex/substrate" } diff --git a/LICENSE b/LICENSE index 0b4b21fc..34f2feb2 100644 --- a/LICENSE +++ b/LICENSE @@ -4,3 +4,5 @@ depending on the crate in question. Each crate declares their license in their a full copy of the AGPL-3.0 License is included in the root of this repository as a reference text. This copy should be provided with any distribution of a crate licensed under the AGPL-3.0, as per its terms. + +The GitHub actions (`.github/actions`) are licensed under the MIT license. diff --git a/README.md b/README.md index e2713106..5b90cb10 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # Serai Serai is a new DEX, built from the ground up, initially planning on listing -Bitcoin, Ethereum, Monero, DAI, offering a liquidity pool trading experience. -Funds are stored in an economically secured threshold multisig wallet. +Bitcoin, Ethereum, DAI, and Monero, offering a liquidity-pool-based trading +experience. Funds are stored in an economically secured threshold-multisig +wallet. [Getting Started](docs/Getting%20Started.md) @@ -10,6 +11,9 @@ Funds are stored in an economically secured threshold multisig wallet. - `docs`: Documentation on the Serai protocol. +- `common`: Crates containing utilities common to a variety of areas under + Serai, none neatly fitting under another category. + - `crypto`: A series of composable cryptographic libraries built around the `ff`/`group` APIs achieving a variety of tasks. These range from generic infrastructure, to our IETF-compliant FROST implementation, to a DLEq proof as @@ -22,13 +26,14 @@ Funds are stored in an economically secured threshold multisig wallet. - `processor`: A generic chain processor to process data for Serai and process events from Serai, executing transactions as expected and needed. -- `contracts`: Smart Contracts implementing Serai's functionality. - - `substrate`: Substrate crates used to instantiate the Serai network. +- `deploy`: Scripts to deploy a Serai node/test environment. + ### Links - [Twitter](https://twitter.com/SeraiDEX): https://twitter.com/SeraiDEX +- [Mastodon](https://cryptodon.lol/@serai): https://cryptodon.lol/@serai - [Discord](https://discord.gg/mpEUtJR3vz): https://discord.gg/mpEUtJR3vz - [Matrix](https://matrix.to/#/#serai:matrix.org): https://matrix.to/#/#serai:matrix.org diff --git a/coins/bitcoin/Cargo.toml b/coins/bitcoin/Cargo.toml new file mode 100644 index 00000000..e9d33c72 --- /dev/null +++ b/coins/bitcoin/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "bitcoin-serai" +version = "0.1.0" +description = "A Bitcoin library for FROST-signing transactions" +license = "MIT" +repository = "https://github.com/serai-dex/serai/tree/develop/coins/bitcoin" +authors = ["Luke Parker ", "Vrx "] +edition = "2021" + +[dependencies] +lazy_static = "1" +thiserror = "1" + +rand_core = "0.6" + +sha2 = "0.10" + +secp256k1 = { version = "0.24", features = ["global-context"] } +bitcoin = { version = "0.29", features = ["serde"] } + +k256 = { version = "0.11", features = ["arithmetic"] } +transcript = { package = "flexible-transcript", path = "../../crypto/transcript", version = "0.2", features = ["recommended"] } +frost = { version = "0.5", package = "modular-frost", path = "../../crypto/frost", features = ["secp256k1"] } + +hex = "0.4" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +reqwest = { version = "0.11", features = ["json"] } + +[dev-dependencies] +frost = { version = "0.5", package = "modular-frost", path = "../../crypto/frost", features = ["tests"] } diff --git a/coins/bitcoin/LICENSE b/coins/bitcoin/LICENSE new file mode 100644 index 00000000..6779f0ec --- /dev/null +++ b/coins/bitcoin/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2023 Luke Parker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/coins/bitcoin/src/crypto.rs b/coins/bitcoin/src/crypto.rs new file mode 100644 index 00000000..73e2077d --- /dev/null +++ b/coins/bitcoin/src/crypto.rs @@ -0,0 +1,61 @@ +use lazy_static::lazy_static; + +use sha2::{Digest, Sha256}; + +use k256::{ + elliptic_curve::{ + ops::Reduce, + sec1::{Tag, ToEncodedPoint}, + }, + U256, Scalar, ProjectivePoint, +}; + +use bitcoin::XOnlyPublicKey; + +use frost::{algorithm::Hram, curve::Secp256k1}; + +/// Get the x coordinate of a non-infinity, even point. Panics on invalid input. +pub fn x(key: &ProjectivePoint) -> [u8; 32] { + let encoded = key.to_encoded_point(true); + assert_eq!(encoded.tag(), Tag::CompressedEvenY); + (*encoded.x().expect("point at infinity")).into() +} + +/// Convert a non-infinite even point to a XOnlyPublicKey. Panics on invalid input. +pub fn x_only(key: &ProjectivePoint) -> XOnlyPublicKey { + XOnlyPublicKey::from_slice(&x(key)).unwrap() +} + +/// Make a point even, returning the even version and the offset required for it to be even. +pub fn make_even(mut key: ProjectivePoint) -> (ProjectivePoint, u64) { + let mut c = 0; + while key.to_encoded_point(true).tag() == Tag::CompressedOddY { + key += ProjectivePoint::GENERATOR; + c += 1; + } + (key, c) +} + +/// A BIP-340 compatible HRAm for use with the modular-frost Schnorr Algorithm. +#[derive(Clone, Copy, Debug)] +pub struct BitcoinHram {} + +lazy_static! { + static ref TAG_HASH: [u8; 32] = Sha256::digest(b"BIP0340/challenge").into(); +} + +#[allow(non_snake_case)] +impl Hram for BitcoinHram { + fn hram(R: &ProjectivePoint, A: &ProjectivePoint, m: &[u8]) -> Scalar { + let (R, _) = make_even(*R); + + let mut data = Sha256::new(); + data.update(*TAG_HASH); + data.update(*TAG_HASH); + data.update(x(&R)); + data.update(x(A)); + data.update(m); + + Scalar::from_uint_reduced(U256::from_be_slice(&data.finalize())) + } +} diff --git a/coins/bitcoin/src/lib.rs b/coins/bitcoin/src/lib.rs new file mode 100644 index 00000000..cdd28b9c --- /dev/null +++ b/coins/bitcoin/src/lib.rs @@ -0,0 +1,9 @@ +/// Cryptographic helpers. +pub mod crypto; +/// Wallet functionality to create transactions. +pub mod wallet; +/// A minimal async RPC. +pub mod rpc; + +#[cfg(test)] +mod tests; diff --git a/coins/bitcoin/src/rpc.rs b/coins/bitcoin/src/rpc.rs new file mode 100644 index 00000000..1ae84916 --- /dev/null +++ b/coins/bitcoin/src/rpc.rs @@ -0,0 +1,80 @@ +use core::fmt::Debug; + +use thiserror::Error; + +use serde::{Deserialize, de::DeserializeOwned}; +use serde_json::json; + +use bitcoin::{ + hashes::hex::{FromHex, ToHex}, + consensus::encode, + Txid, Transaction, BlockHash, Block, +}; + +#[derive(Clone, Debug, Deserialize)] +#[serde(untagged)] +pub(crate) enum RpcResponse { + Ok { result: T }, + Err { error: String }, +} + +#[derive(Clone, Debug)] +pub struct Rpc(String); + +#[derive(Clone, PartialEq, Eq, Debug, Error)] +pub enum RpcError { + #[error("couldn't connect to node")] + ConnectionError, + #[error("request had an error: {0}")] + RequestError(String), + #[error("node sent an invalid response")] + InvalidResponse, +} + +impl Rpc { + pub fn new(url: String) -> Rpc { + Rpc(url) + } + + pub async fn rpc_call( + &self, + method: &str, + params: serde_json::Value, + ) -> Result { + let client = reqwest::Client::new(); + let res = client + .post(&self.0) + .json(&json!({ "jsonrpc": "2.0", "method": method, "params": params })) + .send() + .await + .map_err(|_| RpcError::ConnectionError)? + .text() + .await + .map_err(|_| RpcError::ConnectionError)?; + + let res: RpcResponse = + serde_json::from_str(&res).map_err(|_| RpcError::InvalidResponse)?; + match res { + RpcResponse::Ok { result } => Ok(result), + RpcResponse::Err { error } => Err(RpcError::RequestError(error)), + } + } + + pub async fn get_latest_block_number(&self) -> Result { + self.rpc_call("getblockcount", json!([])).await + } + + pub async fn get_block_hash(&self, number: usize) -> Result { + self.rpc_call("getblockhash", json!([number])).await + } + + pub async fn get_block(&self, block_hash: &BlockHash) -> Result { + let hex = self.rpc_call::("getblock", json!([block_hash.to_hex(), 0])).await?; + let bytes: Vec = FromHex::from_hex(&hex).map_err(|_| RpcError::InvalidResponse)?; + encode::deserialize(&bytes).map_err(|_| RpcError::InvalidResponse) + } + + pub async fn send_raw_transaction(&self, tx: &Transaction) -> Result { + self.rpc_call("sendrawtransaction", json!([encode::serialize_hex(tx)])).await + } +} diff --git a/coins/bitcoin/src/tests/mod.rs b/coins/bitcoin/src/tests/mod.rs new file mode 100644 index 00000000..20be306a --- /dev/null +++ b/coins/bitcoin/src/tests/mod.rs @@ -0,0 +1,47 @@ +use rand_core::OsRng; + +use sha2::{Digest, Sha256}; + +use secp256k1::{SECP256K1, Message, schnorr::Signature}; +use bitcoin::hashes::{Hash as HashTrait, sha256::Hash}; + +use k256::Scalar; +use frost::{ + curve::Secp256k1, + algorithm::Schnorr, + tests::{algorithm_machines, key_gen, sign}, +}; + +use crate::crypto::{BitcoinHram, x_only, make_even}; + +#[test] +fn test_signing() { + let mut keys = key_gen::<_, Secp256k1>(&mut OsRng); + const MESSAGE: &[u8] = b"Hello, World!"; + + for (_, keys) in keys.iter_mut() { + let (_, offset) = make_even(keys.group_key()); + *keys = keys.offset(Scalar::from(offset)); + } + + let algo = Schnorr::::new(); + let mut sig = sign( + &mut OsRng, + algo, + keys.clone(), + algorithm_machines(&mut OsRng, Schnorr::::new(), &keys), + &Sha256::digest(MESSAGE), + ); + + let offset; + (sig.R, offset) = make_even(sig.R); + sig.s += Scalar::from(offset); + + SECP256K1 + .verify_schnorr( + &Signature::from_slice(&sig.serialize()[1 .. 65]).unwrap(), + &Message::from(Hash::hash(MESSAGE)), + &x_only(&keys[&1].group_key()), + ) + .unwrap() +} diff --git a/coins/bitcoin/src/wallet.rs b/coins/bitcoin/src/wallet.rs new file mode 100644 index 00000000..d5905db9 --- /dev/null +++ b/coins/bitcoin/src/wallet.rs @@ -0,0 +1,327 @@ +use std::{ + io::{self, Read, Write}, + collections::HashMap, +}; + +use rand_core::RngCore; + +use transcript::{Transcript, RecommendedTranscript}; + +use k256::{elliptic_curve::sec1::ToEncodedPoint, Scalar}; +use frost::{ + curve::{Ciphersuite, Secp256k1}, + ThresholdKeys, FrostError, + algorithm::Schnorr, + sign::*, +}; + +use bitcoin::{ + hashes::Hash, + consensus::encode::{Decodable, serialize}, + util::sighash::{SchnorrSighashType, SighashCache, Prevouts}, + OutPoint, Script, Sequence, Witness, TxIn, TxOut, PackedLockTime, Transaction, Address, +}; + +use crate::crypto::{BitcoinHram, make_even}; + +/// A spendable output. +#[derive(Clone, Debug)] +pub struct SpendableOutput { + /// The scalar offset to obtain the key usable to spend this output. + /// Enables HDKD systems. + pub offset: Scalar, + /// The output to spend. + pub output: TxOut, + /// The TX ID and vout of the output to spend. + pub outpoint: OutPoint, +} + +impl SpendableOutput { + /// Obtain a unique ID for this output. + pub fn id(&self) -> [u8; 36] { + serialize(&self.outpoint).try_into().unwrap() + } + + /// Read a SpendableOutput from a generic satisfying Read. + pub fn read(r: &mut R) -> io::Result { + Ok(SpendableOutput { + offset: Secp256k1::read_F(r)?, + output: TxOut::consensus_decode(r) + .map_err(|_| io::Error::new(io::ErrorKind::Other, "invalid TxOut"))?, + outpoint: OutPoint::consensus_decode(r) + .map_err(|_| io::Error::new(io::ErrorKind::Other, "invalid OutPoint"))?, + }) + } + + /// Write a SpendableOutput to a generic satisfying Write. + pub fn write(&self, w: &mut W) -> io::Result<()> { + w.write_all(&self.offset.to_bytes())?; + w.write_all(&serialize(&self.output))?; + w.write_all(&serialize(&self.outpoint)) + } + + /// Serialize a SpendableOutput to a Vec. + pub fn serialize(&self) -> Vec { + let mut res = vec![]; + self.write(&mut res).unwrap(); + res + } +} + +/// A signable transaction, clone-able across attempts. +#[derive(Clone, Debug)] +pub struct SignableTransaction(Transaction, Vec, Vec); + +impl SignableTransaction { + fn calculate_weight(inputs: usize, payments: &[(Address, u64)], change: Option<&Address>) -> u64 { + let mut tx = Transaction { + version: 2, + lock_time: PackedLockTime::ZERO, + input: vec![ + TxIn { + previous_output: OutPoint::default(), + script_sig: Script::new(), + sequence: Sequence::MAX, + witness: Witness::from_vec(vec![vec![0; 64]]) + }; + inputs + ], + output: payments + .iter() + .map(|payment| TxOut { value: payment.1, script_pubkey: payment.0.script_pubkey() }) + .collect(), + }; + if let Some(change) = change { + tx.output.push(TxOut { value: 0, script_pubkey: change.script_pubkey() }); + } + u64::try_from(tx.weight()).unwrap() + } + + /// Create a new signable-transaction. + pub fn new( + mut inputs: Vec, + payments: &[(Address, u64)], + change: Option
, + fee: u64, + ) -> Option { + let input_sat = inputs.iter().map(|input| input.output.value).sum::(); + let offsets = inputs.iter().map(|input| input.offset).collect(); + let tx_ins = inputs + .iter() + .map(|input| TxIn { + previous_output: input.outpoint, + script_sig: Script::new(), + sequence: Sequence::MAX, + witness: Witness::new(), + }) + .collect::>(); + + let payment_sat = payments.iter().map(|payment| payment.1).sum::(); + let mut tx_outs = payments + .iter() + .map(|payment| TxOut { value: payment.1, script_pubkey: payment.0.script_pubkey() }) + .collect::>(); + + let actual_fee = fee * Self::calculate_weight(tx_ins.len(), payments, None); + if payment_sat > (input_sat - actual_fee) { + return None; + } + + // If there's a change address, check if there's a meaningful change + if let Some(change) = change.as_ref() { + let fee_with_change = fee * Self::calculate_weight(tx_ins.len(), payments, Some(change)); + // If there's a non-zero change, add it + if let Some(value) = input_sat.checked_sub(payment_sat + fee_with_change) { + tx_outs.push(TxOut { value, script_pubkey: change.script_pubkey() }); + } + } + + // TODO: Drop outputs which BTC will consider spam (outputs worth less than the cost to spend + // them) + + Some(SignableTransaction( + Transaction { version: 2, lock_time: PackedLockTime::ZERO, input: tx_ins, output: tx_outs }, + offsets, + inputs.drain(..).map(|input| input.output).collect(), + )) + } + + /// Create a multisig machine for this transaction. + pub async fn multisig( + self, + keys: ThresholdKeys, + mut transcript: RecommendedTranscript, + ) -> Result { + transcript.domain_separate(b"bitcoin_transaction"); + transcript.append_message(b"root_key", keys.group_key().to_encoded_point(true).as_bytes()); + + // Transcript the inputs and outputs + let tx = &self.0; + for input in &tx.input { + transcript.append_message(b"input_hash", input.previous_output.txid.as_hash().into_inner()); + transcript.append_message(b"input_output_index", input.previous_output.vout.to_le_bytes()); + } + for payment in &tx.output { + transcript.append_message(b"output_script", payment.script_pubkey.as_bytes()); + transcript.append_message(b"output_amount", payment.value.to_le_bytes()); + } + + let mut sigs = vec![]; + for i in 0 .. tx.input.len() { + // TODO: Use the above transcript here + sigs.push( + AlgorithmMachine::new( + Schnorr::::new(), + keys.clone().offset(self.1[i]), + ) + .unwrap(), + ); + } + + Ok(TransactionMachine { tx: self, transcript, sigs }) + } +} + +/// A FROST signing machine to produce a Bitcoin transaction. +pub struct TransactionMachine { + tx: SignableTransaction, + transcript: RecommendedTranscript, + sigs: Vec>>, +} + +impl PreprocessMachine for TransactionMachine { + type Preprocess = Vec>; + type Signature = Transaction; + type SignMachine = TransactionSignMachine; + + fn preprocess( + mut self, + rng: &mut R, + ) -> (Self::SignMachine, Self::Preprocess) { + let mut preprocesses = Vec::with_capacity(self.sigs.len()); + let sigs = self + .sigs + .drain(..) + .map(|sig| { + let (sig, preprocess) = sig.preprocess(rng); + preprocesses.push(preprocess); + sig + }) + .collect(); + + (TransactionSignMachine { tx: self.tx, transcript: self.transcript, sigs }, preprocesses) + } +} + +pub struct TransactionSignMachine { + tx: SignableTransaction, + transcript: RecommendedTranscript, + sigs: Vec>>, +} + +impl SignMachine for TransactionSignMachine { + type Params = (); + type Keys = ThresholdKeys; + type Preprocess = Vec>; + type SignatureShare = Vec>; + type SignatureMachine = TransactionSignatureMachine; + + fn cache(self) -> CachedPreprocess { + unimplemented!( + "Bitcoin transactions don't support caching their preprocesses due to {}", + "being already bound to a specific transaction" + ); + } + + fn from_cache( + _: (), + _: ThresholdKeys, + _: CachedPreprocess, + ) -> Result { + unimplemented!( + "Bitcoin transactions don't support caching their preprocesses due to {}", + "being already bound to a specific transaction" + ); + } + + fn read_preprocess(&self, reader: &mut R) -> io::Result { + self.sigs.iter().map(|sig| sig.read_preprocess(reader)).collect() + } + + fn sign( + mut self, + commitments: HashMap, + msg: &[u8], + ) -> Result<(TransactionSignatureMachine, Self::SignatureShare), FrostError> { + if !msg.is_empty() { + Err(FrostError::InternalError( + "message was passed to the TransactionMachine when it generates its own", + ))?; + } + + let commitments = (0 .. self.sigs.len()) + .map(|c| { + commitments + .iter() + .map(|(l, commitments)| (*l, commitments[c].clone())) + .collect::>() + }) + .collect::>(); + + let mut cache = SighashCache::new(&self.tx.0); + let prevouts = Prevouts::All(&self.tx.2); + + let mut shares = Vec::with_capacity(self.sigs.len()); + let sigs = self + .sigs + .drain(..) + .enumerate() + .map(|(i, sig)| { + let tx_sighash = cache + .taproot_key_spend_signature_hash(i, &prevouts, SchnorrSighashType::Default) + .unwrap(); + + let (sig, share) = sig.sign(commitments[i].clone(), &tx_sighash)?; + shares.push(share); + Ok(sig) + }) + .collect::>()?; + + Ok((TransactionSignatureMachine { tx: self.tx.0, sigs }, shares)) + } +} + +pub struct TransactionSignatureMachine { + tx: Transaction, + sigs: Vec>>, +} + +impl SignatureMachine for TransactionSignatureMachine { + type SignatureShare = Vec>; + + fn read_share(&self, reader: &mut R) -> io::Result { + self.sigs.iter().map(|sig| sig.read_share(reader)).collect() + } + + fn complete( + mut self, + mut shares: HashMap, + ) -> Result { + for (input, schnorr) in self.tx.input.iter_mut().zip(self.sigs.drain(..)) { + let mut sig = schnorr.complete( + shares.iter_mut().map(|(l, shares)| (*l, shares.remove(0))).collect::>(), + )?; + + // TODO: Implement BitcoinSchnorr Algorithm to handle this + let offset; + (sig.R, offset) = make_even(sig.R); + sig.s += Scalar::from(offset); + + let mut witness: Witness = Witness::new(); + witness.push(&sig.serialize()[1 .. 65]); + input.witness = witness; + } + + Ok(self.tx) + } +} diff --git a/coins/ethereum/LICENSE b/coins/ethereum/LICENSE index d6e1814a..c425427c 100644 --- a/coins/ethereum/LICENSE +++ b/coins/ethereum/LICENSE @@ -1,6 +1,6 @@ AGPL-3.0-only license -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 as diff --git a/coins/monero/Cargo.toml b/coins/monero/Cargo.toml index 4093f745..53401d35 100644 --- a/coins/monero/Cargo.toml +++ b/coins/monero/Cargo.toml @@ -14,6 +14,7 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] lazy_static = "1" thiserror = "1" +crc = "3" rand_core = "0.6" rand_chacha = { version = "0.3", optional = true } @@ -24,11 +25,10 @@ zeroize = { version = "^1.5", features = ["zeroize_derive"] } subtle = "^2.4" sha3 = "0.10" -blake2 = { version = "0.10", optional = true } curve25519-dalek = { version = "^3.2", features = ["std"] } -group = { version = "0.12" } +group = "0.12" dalek-ff-group = { path = "../../crypto/dalek-ff-group", version = "0.1" } multiexp = { path = "../../crypto/multiexp", version = "0.2", features = ["batch"] } @@ -56,8 +56,9 @@ monero-generators = { path = "generators", version = "0.1" } hex-literal = "0.3" tokio = { version = "1", features = ["full"] } +monero-rpc = "0.3" frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.5", features = ["ed25519", "tests"] } [features] -multisig = ["rand_chacha", "blake2", "transcript", "frost", "dleq"] +multisig = ["rand_chacha", "transcript", "frost", "dleq"] diff --git a/coins/monero/LICENSE b/coins/monero/LICENSE index f05b748b..6779f0ec 100644 --- a/coins/monero/LICENSE +++ b/coins/monero/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/coins/monero/generators/LICENSE b/coins/monero/generators/LICENSE index f05b748b..6779f0ec 100644 --- a/coins/monero/generators/LICENSE +++ b/coins/monero/generators/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/coins/monero/generators/src/varint.rs b/coins/monero/generators/src/varint.rs index e0aa6a3b..632f658d 100644 --- a/coins/monero/generators/src/varint.rs +++ b/coins/monero/generators/src/varint.rs @@ -1,7 +1,7 @@ -use std::io; +use std::io::{self, Write}; const VARINT_CONTINUATION_MASK: u8 = 0b1000_0000; -pub(crate) fn write_varint(varint: &u64, w: &mut W) -> io::Result<()> { +pub(crate) fn write_varint(varint: &u64, w: &mut W) -> io::Result<()> { let mut varint = *varint; while { let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap(); diff --git a/coins/monero/src/block.rs b/coins/monero/src/block.rs index ea4f3b98..72178d17 100644 --- a/coins/monero/src/block.rs +++ b/coins/monero/src/block.rs @@ -1,3 +1,5 @@ +use std::io::{self, Read, Write}; + use crate::{serialize::*, transaction::Transaction}; #[derive(Clone, PartialEq, Eq, Debug)] @@ -10,7 +12,7 @@ pub struct BlockHeader { } impl BlockHeader { - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { + pub fn write(&self, w: &mut W) -> io::Result<()> { write_varint(&self.major_version, w)?; write_varint(&self.minor_version, w)?; write_varint(&self.timestamp, w)?; @@ -18,7 +20,13 @@ impl BlockHeader { w.write_all(&self.nonce.to_le_bytes()) } - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn serialize(&self) -> Vec { + let mut serialized = vec![]; + self.write(&mut serialized).unwrap(); + serialized + } + + pub fn read(r: &mut R) -> io::Result { Ok(BlockHeader { major_version: read_varint(r)?, minor_version: read_varint(r)?, @@ -37,9 +45,9 @@ pub struct Block { } impl Block { - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { - self.header.serialize(w)?; - self.miner_tx.serialize(w)?; + pub fn write(&self, w: &mut W) -> io::Result<()> { + self.header.write(w)?; + self.miner_tx.write(w)?; write_varint(&self.txs.len().try_into().unwrap(), w)?; for tx in &self.txs { w.write_all(tx)?; @@ -47,10 +55,16 @@ impl Block { Ok(()) } - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn serialize(&self) -> Vec { + let mut serialized = vec![]; + self.write(&mut serialized).unwrap(); + serialized + } + + pub fn read(r: &mut R) -> io::Result { Ok(Block { - header: BlockHeader::deserialize(r)?, - miner_tx: Transaction::deserialize(r)?, + header: BlockHeader::read(r)?, + miner_tx: Transaction::read(r)?, txs: (0 .. read_varint(r)?).map(|_| read_bytes(r)).collect::>()?, }) } diff --git a/coins/monero/src/lib.rs b/coins/monero/src/lib.rs index e1574cf7..cc6b325e 100644 --- a/coins/monero/src/lib.rs +++ b/coins/monero/src/lib.rs @@ -56,7 +56,6 @@ mod tests; #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] #[allow(non_camel_case_types)] pub enum Protocol { - Unsupported(usize), v14, v16, Custom { ring_len: usize, bp_plus: bool }, @@ -66,7 +65,6 @@ impl Protocol { /// Amount of ring members under this protocol version. pub fn ring_len(&self) -> usize { match self { - Protocol::Unsupported(_) => panic!("Unsupported protocol version"), Protocol::v14 => 11, Protocol::v16 => 16, Protocol::Custom { ring_len, .. } => *ring_len, @@ -77,7 +75,6 @@ impl Protocol { /// This method will likely be reworked when versions not using Bulletproofs at all are added. pub fn bp_plus(&self) -> bool { match self { - Protocol::Unsupported(_) => panic!("Unsupported protocol version"), Protocol::v14 => false, Protocol::v16 => true, Protocol::Custom { bp_plus, .. } => *bp_plus, diff --git a/coins/monero/src/ringct/bulletproofs/mod.rs b/coins/monero/src/ringct/bulletproofs/mod.rs index 227890d3..fdddca2a 100644 --- a/coins/monero/src/ringct/bulletproofs/mod.rs +++ b/coins/monero/src/ringct/bulletproofs/mod.rs @@ -1,5 +1,7 @@ #![allow(non_snake_case)] +use std::io::{self, Read, Write}; + use rand_core::{RngCore, CryptoRng}; use zeroize::Zeroize; @@ -35,6 +37,7 @@ impl Bulletproofs { pub(crate) fn fee_weight(plus: bool, outputs: usize) -> usize { let fields = if plus { 6 } else { 9 }; + // TODO: Shouldn't this use u32/u64? #[allow(non_snake_case)] let mut LR_len = usize::try_from(usize::BITS - (outputs - 1).leading_zeros()).unwrap(); let padded_outputs = 1 << LR_len; @@ -93,11 +96,11 @@ impl Bulletproofs { } } - fn serialize_core std::io::Result<()>>( + fn write_core io::Result<()>>( &self, w: &mut W, specific_write_vec: F, - ) -> std::io::Result<()> { + ) -> io::Result<()> { match self { Bulletproofs::Original(bp) => { write_point(&bp.A, w)?; @@ -126,16 +129,22 @@ impl Bulletproofs { } } - pub(crate) fn signature_serialize(&self, w: &mut W) -> std::io::Result<()> { - self.serialize_core(w, |points, w| write_raw_vec(write_point, points, w)) + pub(crate) fn signature_write(&self, w: &mut W) -> io::Result<()> { + self.write_core(w, |points, w| write_raw_vec(write_point, points, w)) } - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { - self.serialize_core(w, |points, w| write_vec(write_point, points, w)) + pub fn write(&self, w: &mut W) -> io::Result<()> { + self.write_core(w, |points, w| write_vec(write_point, points, w)) } - /// Deserialize non-plus Bulletproofs. - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn serialize(&self) -> Vec { + let mut serialized = vec![]; + self.write(&mut serialized).unwrap(); + serialized + } + + /// Read Bulletproofs. + pub fn read(r: &mut R) -> io::Result { Ok(Bulletproofs::Original(OriginalStruct { A: read_point(r)?, S: read_point(r)?, @@ -151,8 +160,8 @@ impl Bulletproofs { })) } - /// Deserialize Bulletproofs+. - pub fn deserialize_plus(r: &mut R) -> std::io::Result { + /// Read Bulletproofs+. + pub fn read_plus(r: &mut R) -> io::Result { Ok(Bulletproofs::Plus(PlusStruct { A: read_point(r)?, A1: read_point(r)?, diff --git a/coins/monero/src/ringct/clsag/mod.rs b/coins/monero/src/ringct/clsag/mod.rs index 2d9ba830..249661f9 100644 --- a/coins/monero/src/ringct/clsag/mod.rs +++ b/coins/monero/src/ringct/clsag/mod.rs @@ -1,6 +1,7 @@ #![allow(non_snake_case)] use core::ops::Deref; +use std::io::{self, Read, Write}; use lazy_static::lazy_static; use thiserror::Error; @@ -313,13 +314,13 @@ impl Clsag { (ring_len * 32) + 32 + 32 } - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { + pub fn write(&self, w: &mut W) -> io::Result<()> { write_raw_vec(write_scalar, &self.s, w)?; w.write_all(&self.c1.to_bytes())?; write_point(&self.D, w) } - pub fn deserialize(decoys: usize, r: &mut R) -> std::io::Result { + pub fn read(decoys: usize, r: &mut R) -> io::Result { Ok(Clsag { s: read_raw_vec(read_scalar, decoys, r)?, c1: read_scalar(r)?, D: read_point(r)? }) } } diff --git a/coins/monero/src/ringct/clsag/multisig.rs b/coins/monero/src/ringct/clsag/multisig.rs index d9f3b5f3..78e44fe9 100644 --- a/coins/monero/src/ringct/clsag/multisig.rs +++ b/coins/monero/src/ringct/clsag/multisig.rs @@ -41,18 +41,17 @@ impl ClsagInput { // Doesn't domain separate as this is considered part of the larger CLSAG proof // Ring index - transcript.append_message(b"ring_index", [self.decoys.i]); + transcript.append_message(b"real_spend", [self.decoys.i]); // Ring - let mut ring = vec![]; - for pair in &self.decoys.ring { + for (i, pair) in self.decoys.ring.iter().enumerate() { // Doesn't include global output indexes as CLSAG doesn't care and won't be affected by it // They're just a unreliable reference to this data which will be included in the message // if in use - ring.extend(pair[0].compress().to_bytes()); - ring.extend(pair[1].compress().to_bytes()); + transcript.append_message(b"member", [u8::try_from(i).expect("ring size exceeded 255")]); + transcript.append_message(b"key", pair[0].compress().to_bytes()); + transcript.append_message(b"commitment", pair[1].compress().to_bytes()) } - transcript.append_message(b"ring", ring); // Doesn't include the commitment's parts as the above ring + index includes the commitment // The only potential malleability would be if the G/H relationship is known breaking the diff --git a/coins/monero/src/ringct/mod.rs b/coins/monero/src/ringct/mod.rs index b81e8651..d289b6f1 100644 --- a/coins/monero/src/ringct/mod.rs +++ b/coins/monero/src/ringct/mod.rs @@ -1,4 +1,5 @@ use core::ops::Deref; +use std::io::{self, Read, Write}; use zeroize::Zeroizing; @@ -35,7 +36,7 @@ impl RctBase { 1 + 8 + (outputs * (8 + 32)) } - pub fn serialize(&self, w: &mut W, rct_type: u8) -> std::io::Result<()> { + pub fn write(&self, w: &mut W, rct_type: u8) -> io::Result<()> { w.write_all(&[rct_type])?; match rct_type { 0 => Ok(()), @@ -50,10 +51,7 @@ impl RctBase { } } - pub fn deserialize( - outputs: usize, - r: &mut R, - ) -> std::io::Result<(RctBase, u8)> { + pub fn read(outputs: usize, r: &mut R) -> io::Result<(RctBase, u8)> { let rct_type = read_byte(r)?; Ok(( if rct_type == 0 { @@ -96,46 +94,43 @@ impl RctPrunable { (inputs * (Clsag::fee_weight(protocol.ring_len()) + 32)) } - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { + pub fn write(&self, w: &mut W) -> io::Result<()> { match self { RctPrunable::Null => Ok(()), RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs, .. } => { - write_vec(Bulletproofs::serialize, bulletproofs, w)?; - write_raw_vec(Clsag::serialize, clsags, w)?; + write_vec(Bulletproofs::write, bulletproofs, w)?; + write_raw_vec(Clsag::write, clsags, w)?; write_raw_vec(write_point, pseudo_outs, w) } } } - pub fn deserialize( - rct_type: u8, - decoys: &[usize], - r: &mut R, - ) -> std::io::Result { + pub fn serialize(&self) -> Vec { + let mut serialized = vec![]; + self.write(&mut serialized).unwrap(); + serialized + } + + pub fn read(rct_type: u8, decoys: &[usize], r: &mut R) -> io::Result { Ok(match rct_type { 0 => RctPrunable::Null, 5 | 6 => RctPrunable::Clsag { bulletproofs: read_vec( - if rct_type == 5 { Bulletproofs::deserialize } else { Bulletproofs::deserialize_plus }, + if rct_type == 5 { Bulletproofs::read } else { Bulletproofs::read_plus }, r, )?, - clsags: (0 .. decoys.len()) - .map(|o| Clsag::deserialize(decoys[o], r)) - .collect::>()?, + clsags: (0 .. decoys.len()).map(|o| Clsag::read(decoys[o], r)).collect::>()?, pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?, }, - _ => Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Tried to deserialize unknown RCT type", - ))?, + _ => Err(io::Error::new(io::ErrorKind::Other, "Tried to deserialize unknown RCT type"))?, }) } - pub(crate) fn signature_serialize(&self, w: &mut W) -> std::io::Result<()> { + pub(crate) fn signature_write(&self, w: &mut W) -> io::Result<()> { match self { RctPrunable::Null => panic!("Serializing RctPrunable::Null for a signature"), RctPrunable::Clsag { bulletproofs, .. } => { - bulletproofs.iter().try_for_each(|bp| bp.signature_serialize(w)) + bulletproofs.iter().try_for_each(|bp| bp.signature_write(w)) } } } @@ -152,17 +147,19 @@ impl RctSignatures { RctBase::fee_weight(outputs) + RctPrunable::fee_weight(protocol, inputs, outputs) } - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { - self.base.serialize(w, self.prunable.rct_type())?; - self.prunable.serialize(w) + pub fn write(&self, w: &mut W) -> io::Result<()> { + self.base.write(w, self.prunable.rct_type())?; + self.prunable.write(w) } - pub fn deserialize( - decoys: Vec, - outputs: usize, - r: &mut R, - ) -> std::io::Result { - let base = RctBase::deserialize(outputs, r)?; - Ok(RctSignatures { base: base.0, prunable: RctPrunable::deserialize(base.1, &decoys, r)? }) + pub fn serialize(&self) -> Vec { + let mut serialized = vec![]; + self.write(&mut serialized).unwrap(); + serialized + } + + pub fn read(decoys: Vec, outputs: usize, r: &mut R) -> io::Result { + let base = RctBase::read(outputs, r)?; + Ok(RctSignatures { base: base.0, prunable: RctPrunable::read(base.1, &decoys, r)? }) } } diff --git a/coins/monero/src/rpc.rs b/coins/monero/src/rpc.rs index 94bf84ff..f53bfc72 100644 --- a/coins/monero/src/rpc.rs +++ b/coins/monero/src/rpc.rs @@ -27,7 +27,6 @@ pub struct JsonRpcResponse { #[derive(Deserialize, Debug)] struct TransactionResponse { tx_hash: String, - block_height: Option, as_hex: String, pruned_as_hex: String, } @@ -46,6 +45,8 @@ pub enum RpcError { ConnectionError, #[error("invalid node")] InvalidNode, + #[error("unsupported protocol version ({0})")] + UnsupportedProtocol(usize), #[error("transactions not found")] TransactionsNotFound(Vec<[u8; 32]>), #[error("invalid point ({0})")] @@ -212,7 +213,7 @@ impl Rpc { { 13 | 14 => Protocol::v14, 15 | 16 => Protocol::v16, - version => Protocol::Unsupported(version), + protocol => Err(RpcError::UnsupportedProtocol(protocol))?, }, ) } @@ -248,10 +249,12 @@ impl Rpc { txs .txs .iter() - .map(|res| { - let tx = Transaction::deserialize(&mut std::io::Cursor::new(rpc_hex( - if !res.as_hex.is_empty() { &res.as_hex } else { &res.pruned_as_hex }, - )?)) + .enumerate() + .map(|(i, res)| { + let tx = Transaction::read::<&[u8]>( + &mut rpc_hex(if !res.as_hex.is_empty() { &res.as_hex } else { &res.pruned_as_hex })? + .as_ref(), + ) .map_err(|_| match hash_hex(&res.tx_hash) { Ok(hash) => RpcError::InvalidTransaction(hash), Err(err) => err, @@ -265,6 +268,12 @@ impl Rpc { } } + // This does run a few keccak256 hashes, which is pointless if the node is trusted + // In exchange, this provides resilience against invalid/malicious nodes + if tx.hash() != hashes[i] { + Err(RpcError::InvalidNode)?; + } + Ok(tx) }) .collect() @@ -274,40 +283,71 @@ impl Rpc { self.get_transactions(&[tx]).await.map(|mut txs| txs.swap_remove(0)) } - pub async fn get_transaction_block_number(&self, tx: &[u8]) -> Result, RpcError> { - let txs: TransactionsResponse = - self.rpc_call("get_transactions", Some(json!({ "txs_hashes": [hex::encode(tx)] }))).await?; - - if !txs.missed_tx.is_empty() { - Err(RpcError::TransactionsNotFound( - txs.missed_tx.iter().map(|hash| hash_hex(hash)).collect::>()?, - ))?; + /// Get the hash of a block from the node by the block's numbers. + /// This function does not verify the returned block hash is actually for the number in question. + pub async fn get_block_hash(&self, number: usize) -> Result<[u8; 32], RpcError> { + #[derive(Deserialize, Debug)] + struct BlockHeaderResponse { + hash: String, + } + #[derive(Deserialize, Debug)] + struct BlockHeaderByHeightResponse { + block_header: BlockHeaderResponse, } - Ok(txs.txs[0].block_height) + let header: BlockHeaderByHeightResponse = + self.json_rpc_call("get_block_header_by_height", Some(json!({ "height": number }))).await?; + rpc_hex(&header.block_header.hash)?.try_into().map_err(|_| RpcError::InvalidNode) } - pub async fn get_block(&self, height: usize) -> Result { + /// Get a block from the node by its hash. + /// This function does not verify the returned block actually has the hash in question. + pub async fn get_block(&self, hash: [u8; 32]) -> Result { #[derive(Deserialize, Debug)] struct BlockResponse { blob: String, } - let block: BlockResponse = - self.json_rpc_call("get_block", Some(json!({ "height": height }))).await?; - Ok( - Block::deserialize(&mut std::io::Cursor::new(rpc_hex(&block.blob)?)) - .expect("Monero returned a block we couldn't deserialize"), - ) + let res: BlockResponse = + self.json_rpc_call("get_block", Some(json!({ "hash": hex::encode(hash) }))).await?; + + // TODO: Verify the TXs included are actually committed to by the header + Block::read::<&[u8]>(&mut rpc_hex(&res.blob)?.as_ref()).map_err(|_| RpcError::InvalidNode) } - pub async fn get_block_transactions(&self, height: usize) -> Result, RpcError> { - let block = self.get_block(height).await?; + pub async fn get_block_by_number(&self, number: usize) -> Result { + match self.get_block(self.get_block_hash(number).await?).await { + Ok(block) => { + // Make sure this is actually the block for this number + match block.miner_tx.prefix.inputs[0] { + Input::Gen(actual) => { + if usize::try_from(actual).unwrap() == number { + Ok(block) + } else { + Err(RpcError::InvalidNode) + } + } + _ => Err(RpcError::InvalidNode), + } + } + e => e, + } + } + + pub async fn get_block_transactions(&self, hash: [u8; 32]) -> Result, RpcError> { + let block = self.get_block(hash).await?; let mut res = vec![block.miner_tx]; res.extend(self.get_transactions(&block.txs).await?); Ok(res) } + pub async fn get_block_transactions_by_number( + &self, + number: usize, + ) -> Result, RpcError> { + self.get_block_transactions(self.get_block_hash(number).await?).await + } + /// Get the output indexes of the specified transaction. pub async fn get_o_indexes(&self, hash: [u8; 32]) -> Result, RpcError> { #[derive(Serialize, Debug)] @@ -370,8 +410,9 @@ impl Rpc { Ok(distributions.distributions.swap_remove(0).distribution) } - /// Get the specified outputs from the RingCT (zero-amount) pool, but only return them if they're - /// unlocked. + /// Get the specified outputs from the RingCT (zero-amount) pool, but only return them if their + /// timelock has been satisfied. This is distinct from being free of the 10-block lock applied to + /// all Monero transactions. pub async fn get_unlocked_outputs( &self, indexes: &[u64], @@ -407,13 +448,8 @@ impl Rpc { &outs .outs .iter() - .map(|out| { - rpc_hex(&out.txid) - .expect("Monero returned an invalidly encoded hash") - .try_into() - .expect("Monero returned an invalid sized hash") - }) - .collect::>(), + .map(|out| rpc_hex(&out.txid)?.try_into().map_err(|_| RpcError::InvalidNode)) + .collect::, _>>()?, ) .await?; @@ -466,7 +502,7 @@ impl Rpc { } let mut buf = Vec::with_capacity(2048); - tx.serialize(&mut buf).unwrap(); + tx.write(&mut buf).unwrap(); let res: SendRawResponse = self .rpc_call("send_raw_transaction", Some(json!({ "tx_as_hex": hex::encode(&buf) }))) .await?; diff --git a/coins/monero/src/serialize.rs b/coins/monero/src/serialize.rs index 0767d7f2..bc548737 100644 --- a/coins/monero/src/serialize.rs +++ b/coins/monero/src/serialize.rs @@ -1,4 +1,4 @@ -use std::io; +use std::io::{self, Read, Write}; use curve25519_dalek::{ scalar::Scalar, @@ -11,11 +11,11 @@ pub(crate) fn varint_len(varint: usize) -> usize { ((usize::try_from(usize::BITS - varint.leading_zeros()).unwrap().saturating_sub(1)) / 7) + 1 } -pub(crate) fn write_byte(byte: &u8, w: &mut W) -> io::Result<()> { +pub(crate) fn write_byte(byte: &u8, w: &mut W) -> io::Result<()> { w.write_all(&[*byte]) } -pub(crate) fn write_varint(varint: &u64, w: &mut W) -> io::Result<()> { +pub(crate) fn write_varint(varint: &u64, w: &mut W) -> io::Result<()> { let mut varint = *varint; while { let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap(); @@ -29,15 +29,15 @@ pub(crate) fn write_varint(varint: &u64, w: &mut W) -> io::Result< Ok(()) } -pub(crate) fn write_scalar(scalar: &Scalar, w: &mut W) -> io::Result<()> { +pub(crate) fn write_scalar(scalar: &Scalar, w: &mut W) -> io::Result<()> { w.write_all(&scalar.to_bytes()) } -pub(crate) fn write_point(point: &EdwardsPoint, w: &mut W) -> io::Result<()> { +pub(crate) fn write_point(point: &EdwardsPoint, w: &mut W) -> io::Result<()> { w.write_all(&point.compress().to_bytes()) } -pub(crate) fn write_raw_vec io::Result<()>>( +pub(crate) fn write_raw_vec io::Result<()>>( f: F, values: &[T], w: &mut W, @@ -48,7 +48,7 @@ pub(crate) fn write_raw_vec io::Result<()> Ok(()) } -pub(crate) fn write_vec io::Result<()>>( +pub(crate) fn write_vec io::Result<()>>( f: F, values: &[T], w: &mut W, @@ -57,25 +57,25 @@ pub(crate) fn write_vec io::Result<()>>( write_raw_vec(f, values, w) } -pub(crate) fn read_bytes(r: &mut R) -> io::Result<[u8; N]> { +pub(crate) fn read_bytes(r: &mut R) -> io::Result<[u8; N]> { let mut res = [0; N]; r.read_exact(&mut res)?; Ok(res) } -pub(crate) fn read_byte(r: &mut R) -> io::Result { +pub(crate) fn read_byte(r: &mut R) -> io::Result { Ok(read_bytes::<_, 1>(r)?[0]) } -pub(crate) fn read_u64(r: &mut R) -> io::Result { +pub(crate) fn read_u64(r: &mut R) -> io::Result { read_bytes(r).map(u64::from_le_bytes) } -pub(crate) fn read_u32(r: &mut R) -> io::Result { +pub(crate) fn read_u32(r: &mut R) -> io::Result { read_bytes(r).map(u32::from_le_bytes) } -pub(crate) fn read_varint(r: &mut R) -> io::Result { +pub(crate) fn read_varint(r: &mut R) -> io::Result { let mut bits = 0; let mut res = 0; while { @@ -100,12 +100,12 @@ pub(crate) fn read_varint(r: &mut R) -> io::Result { // for now. There's also further edge cases as noted by // https://github.com/monero-project/monero/issues/8438, where some scalars had an archaic // reduction applied -pub(crate) fn read_scalar(r: &mut R) -> io::Result { +pub(crate) fn read_scalar(r: &mut R) -> io::Result { Scalar::from_canonical_bytes(read_bytes(r)?) .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "unreduced scalar")) } -pub(crate) fn read_point(r: &mut R) -> io::Result { +pub(crate) fn read_point(r: &mut R) -> io::Result { let bytes = read_bytes(r)?; CompressedEdwardsY(bytes) .decompress() @@ -114,14 +114,14 @@ pub(crate) fn read_point(r: &mut R) -> io::Result { .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point")) } -pub(crate) fn read_torsion_free_point(r: &mut R) -> io::Result { +pub(crate) fn read_torsion_free_point(r: &mut R) -> io::Result { read_point(r) .ok() .filter(|point| point.is_torsion_free()) .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point")) } -pub(crate) fn read_raw_vec io::Result>( +pub(crate) fn read_raw_vec io::Result>( f: F, len: usize, r: &mut R, @@ -133,7 +133,7 @@ pub(crate) fn read_raw_vec io::Result>( Ok(res) } -pub(crate) fn read_vec io::Result>( +pub(crate) fn read_vec io::Result>( f: F, r: &mut R, ) -> io::Result> { diff --git a/coins/monero/src/tests/address.rs b/coins/monero/src/tests/address.rs index 3c005735..76f75a3e 100644 --- a/coins/monero/src/tests/address.rs +++ b/coins/monero/src/tests/address.rs @@ -33,9 +33,9 @@ fn standard_address() { let addr = MoneroAddress::from_str(Network::Mainnet, STANDARD).unwrap(); assert_eq!(addr.meta.network, Network::Mainnet); assert_eq!(addr.meta.kind, AddressType::Standard); - assert!(!addr.meta.kind.subaddress()); + assert!(!addr.meta.kind.is_subaddress()); assert_eq!(addr.meta.kind.payment_id(), None); - assert!(!addr.meta.kind.guaranteed()); + assert!(!addr.meta.kind.is_guaranteed()); assert_eq!(addr.spend.compress().to_bytes(), SPEND); assert_eq!(addr.view.compress().to_bytes(), VIEW); assert_eq!(addr.to_string(), STANDARD); @@ -46,9 +46,9 @@ fn integrated_address() { let addr = MoneroAddress::from_str(Network::Mainnet, INTEGRATED).unwrap(); assert_eq!(addr.meta.network, Network::Mainnet); assert_eq!(addr.meta.kind, AddressType::Integrated(PAYMENT_ID)); - assert!(!addr.meta.kind.subaddress()); + assert!(!addr.meta.kind.is_subaddress()); assert_eq!(addr.meta.kind.payment_id(), Some(PAYMENT_ID)); - assert!(!addr.meta.kind.guaranteed()); + assert!(!addr.meta.kind.is_guaranteed()); assert_eq!(addr.spend.compress().to_bytes(), SPEND); assert_eq!(addr.view.compress().to_bytes(), VIEW); assert_eq!(addr.to_string(), INTEGRATED); @@ -59,9 +59,9 @@ fn subaddress() { let addr = MoneroAddress::from_str(Network::Mainnet, SUBADDRESS).unwrap(); assert_eq!(addr.meta.network, Network::Mainnet); assert_eq!(addr.meta.kind, AddressType::Subaddress); - assert!(addr.meta.kind.subaddress()); + assert!(addr.meta.kind.is_subaddress()); assert_eq!(addr.meta.kind.payment_id(), None); - assert!(!addr.meta.kind.guaranteed()); + assert!(!addr.meta.kind.is_guaranteed()); assert_eq!(addr.spend.compress().to_bytes(), SUB_SPEND); assert_eq!(addr.view.compress().to_bytes(), SUB_VIEW); assert_eq!(addr.to_string(), SUBADDRESS); @@ -83,13 +83,14 @@ fn featured() { let subaddress = (features & SUBADDRESS_FEATURE_BIT) == SUBADDRESS_FEATURE_BIT; - let mut id = [0; 8]; - OsRng.fill_bytes(&mut id); - let id = Some(id).filter(|_| (features & INTEGRATED_FEATURE_BIT) == INTEGRATED_FEATURE_BIT); + let mut payment_id = [0; 8]; + OsRng.fill_bytes(&mut payment_id); + let payment_id = Some(payment_id) + .filter(|_| (features & INTEGRATED_FEATURE_BIT) == INTEGRATED_FEATURE_BIT); let guaranteed = (features & GUARANTEED_FEATURE_BIT) == GUARANTEED_FEATURE_BIT; - let kind = AddressType::Featured(subaddress, id, guaranteed); + let kind = AddressType::Featured { subaddress, payment_id, guaranteed }; let meta = AddressMeta::new(network, kind); let addr = MoneroAddress::new(meta, spend, view); @@ -99,9 +100,9 @@ fn featured() { assert_eq!(addr.spend, spend); assert_eq!(addr.view, view); - assert_eq!(addr.subaddress(), subaddress); - assert_eq!(addr.payment_id(), id); - assert_eq!(addr.guaranteed(), guaranteed); + assert_eq!(addr.is_subaddress(), subaddress); + assert_eq!(addr.payment_id(), payment_id); + assert_eq!(addr.is_guaranteed(), guaranteed); } } } @@ -150,16 +151,20 @@ fn featured_vectors() { assert_eq!(addr.spend, spend); assert_eq!(addr.view, view); - assert_eq!(addr.subaddress(), vector.subaddress); + assert_eq!(addr.is_subaddress(), vector.subaddress); assert_eq!(vector.integrated, vector.payment_id.is_some()); assert_eq!(addr.payment_id(), vector.payment_id); - assert_eq!(addr.guaranteed(), vector.guaranteed); + assert_eq!(addr.is_guaranteed(), vector.guaranteed); assert_eq!( MoneroAddress::new( AddressMeta::new( network, - AddressType::Featured(vector.subaddress, vector.payment_id, vector.guaranteed) + AddressType::Featured { + subaddress: vector.subaddress, + payment_id: vector.payment_id, + guaranteed: vector.guaranteed + } ), spend, view diff --git a/coins/monero/src/tests/clsag.rs b/coins/monero/src/tests/clsag.rs index 273124e8..70b1b5fe 100644 --- a/coins/monero/src/tests/clsag.rs +++ b/coins/monero/src/tests/clsag.rs @@ -66,7 +66,7 @@ fn clsag() { Commitment::new(secrets.1, AMOUNT), Decoys { i: u8::try_from(real).unwrap(), - offsets: (1 ..= RING_LEN).into_iter().collect(), + offsets: (1 ..= RING_LEN).collect(), ring: ring.clone(), }, ) @@ -110,11 +110,7 @@ fn clsag_multisig() { Arc::new(RwLock::new(Some(ClsagDetails::new( ClsagInput::new( Commitment::new(randomness, AMOUNT), - Decoys { - i: RING_INDEX, - offsets: (1 ..= RING_LEN).into_iter().collect(), - ring: ring.clone(), - }, + Decoys { i: RING_INDEX, offsets: (1 ..= RING_LEN).collect(), ring: ring.clone() }, ) .unwrap(), mask_sum, diff --git a/coins/monero/src/tests/mod.rs b/coins/monero/src/tests/mod.rs index f92473c4..835b77ca 100644 --- a/coins/monero/src/tests/mod.rs +++ b/coins/monero/src/tests/mod.rs @@ -1,3 +1,4 @@ mod clsag; mod bulletproofs; mod address; +mod seed; diff --git a/coins/monero/src/tests/seed.rs b/coins/monero/src/tests/seed.rs new file mode 100644 index 00000000..96bd176d --- /dev/null +++ b/coins/monero/src/tests/seed.rs @@ -0,0 +1,177 @@ +use zeroize::Zeroizing; + +use rand_core::OsRng; + +use curve25519_dalek::scalar::Scalar; + +use crate::{ + hash, + wallet::seed::{Seed, Language, classic::trim_by_lang}, +}; + +#[test] +fn test_classic_seed() { + struct Vector { + language: Language, + seed: String, + spend: String, + view: String, + } + + let vectors = [ + Vector { + language: Language::Chinese, + seed: "摇 曲 艺 武 滴 然 效 似 赏 式 祥 歌 买 疑 小 碧 堆 博 键 房 鲜 悲 付 喷 武".into(), + spend: "a5e4fff1706ef9212993a69f246f5c95ad6d84371692d63e9bb0ea112a58340d".into(), + view: "1176c43ce541477ea2f3ef0b49b25112b084e26b8a843e1304ac4677b74cdf02".into(), + }, + Vector { + language: Language::English, + seed: "washing thirsty occur lectures tuesday fainted toxic adapt \ + abnormal memoir nylon mostly building shrugged online ember northern \ + ruby woes dauntless boil family illness inroads northern" + .into(), + spend: "c0af65c0dd837e666b9d0dfed62745f4df35aed7ea619b2798a709f0fe545403".into(), + view: "513ba91c538a5a9069e0094de90e927c0cd147fa10428ce3ac1afd49f63e3b01".into(), + }, + Vector { + language: Language::Dutch, + seed: "setwinst riphagen vimmetje extase blief tuitelig fuiven meifeest \ + ponywagen zesmaal ripdeal matverf codetaal leut ivoor rotten \ + wisgerhof winzucht typograaf atrium rein zilt traktaat verzaagd setwinst" + .into(), + spend: "e2d2873085c447c2bc7664222ac8f7d240df3aeac137f5ff2022eaa629e5b10a".into(), + view: "eac30b69477e3f68093d131c7fd961564458401b07f8c87ff8f6030c1a0c7301".into(), + }, + Vector { + language: Language::French, + seed: "poids vaseux tarte bazar poivre effet entier nuance \ + sensuel ennui pacte osselet poudre battre alibi mouton \ + stade paquet pliage gibier type question position projet pliage" + .into(), + spend: "2dd39ff1a4628a94b5c2ec3e42fb3dfe15c2b2f010154dc3b3de6791e805b904".into(), + view: "6725b32230400a1032f31d622b44c3a227f88258939b14a7c72e00939e7bdf0e".into(), + }, + Vector { + language: Language::Spanish, + seed: "minero ocupar mirar evadir octubre cal logro miope \ + opaco disco ancla litio clase cuello nasal clase \ + fiar avance deseo mente grumo negro cordón croqueta clase" + .into(), + spend: "ae2c9bebdddac067d73ec0180147fc92bdf9ac7337f1bcafbbe57dd13558eb02".into(), + view: "18deafb34d55b7a43cae2c1c1c206a3c80c12cc9d1f84640b484b95b7fec3e05".into(), + }, + Vector { + language: Language::German, + seed: "Kaliber Gabelung Tapir Liveband Favorit Specht Enklave Nabel \ + Jupiter Foliant Chronik nisten löten Vase Aussage Rekord \ + Yeti Gesetz Eleganz Alraune Künstler Almweide Jahr Kastanie Almweide" + .into(), + spend: "79801b7a1b9796856e2397d862a113862e1fdc289a205e79d8d70995b276db06".into(), + view: "99f0ec556643bd9c038a4ed86edcb9c6c16032c4622ed2e000299d527a792701".into(), + }, + Vector { + language: Language::Italian, + seed: "cavo pancetta auto fulmine alleanza filmato diavolo prato \ + forzare meritare litigare lezione segreto evasione votare buio \ + licenza cliente dorso natale crescere vento tutelare vetta evasione" + .into(), + spend: "5e7fd774eb00fa5877e2a8b4dc9c7ffe111008a3891220b56a6e49ac816d650a".into(), + view: "698a1dce6018aef5516e82ca0cb3e3ec7778d17dfb41a137567bfa2e55e63a03".into(), + }, + Vector { + language: Language::Portuguese, + seed: "agito eventualidade onus itrio holograma sodomizar objetos dobro \ + iugoslavo bcrepuscular odalisca abjeto iuane darwinista eczema acetona \ + cibernetico hoquei gleba driver buffer azoto megera nogueira agito" + .into(), + spend: "13b3115f37e35c6aa1db97428b897e584698670c1b27854568d678e729200c0f".into(), + view: "ad1b4fd35270f5f36c4da7166672b347e75c3f4d41346ec2a06d1d0193632801".into(), + }, + Vector { + language: Language::Japanese, + seed: "ぜんぶ どうぐ おたがい せんきょ おうじ そんちょう じゅしん いろえんぴつ \ + かほう つかれる えらぶ にちじょう くのう にちようび ぬまえび さんきゃく \ + おおや ちぬき うすめる いがく せつでん さうな すいえい せつだん おおや" + .into(), + spend: "c56e895cdb13007eda8399222974cdbab493640663804b93cbef3d8c3df80b0b".into(), + view: "6c3634a313ec2ee979d565c33888fd7c3502d696ce0134a8bc1a2698c7f2c508".into(), + }, + Vector { + language: Language::Russian, + seed: "шатер икра нация ехать получать инерция доза реальный \ + рыжий таможня лопата душа веселый клетка атлас лекция \ + обгонять паек наивный лыжный дурак стать ежик задача паек" + .into(), + spend: "7cb5492df5eb2db4c84af20766391cd3e3662ab1a241c70fc881f3d02c381f05".into(), + view: "fcd53e41ec0df995ab43927f7c44bc3359c93523d5009fb3f5ba87431d545a03".into(), + }, + Vector { + language: Language::Esperanto, + seed: "ukazo klini peco etikedo fabriko imitado onklino urino \ + pudro incidento kumuluso ikono smirgi hirundo uretro krii \ + sparkado super speciala pupo alpinisto cvana vokegi zombio fabriko" + .into(), + spend: "82ebf0336d3b152701964ed41df6b6e9a035e57fc98b84039ed0bd4611c58904".into(), + view: "cd4d120e1ea34360af528f6a3e6156063312d9cefc9aa6b5218d366c0ed6a201".into(), + }, + Vector { + language: Language::Lojban, + seed: "jetnu vensa julne xrotu xamsi julne cutci dakli \ + mlatu xedja muvgau palpi xindo sfubu ciste cinri \ + blabi darno dembi janli blabi fenki bukpu burcu blabi" + .into(), + spend: "e4f8c6819ab6cf792cebb858caabac9307fd646901d72123e0367ebc0a79c200".into(), + view: "c806ce62bafaa7b2d597f1a1e2dbe4a2f96bfd804bf6f8420fc7f4a6bd700c00".into(), + }, + Vector { + language: Language::EnglishOld, + seed: "glorious especially puff son moment add youth nowhere \ + throw glide grip wrong rhythm consume very swear \ + bitter heavy eventually begin reason flirt type unable" + .into(), + spend: "647f4765b66b636ff07170ab6280a9a6804dfbaf19db2ad37d23be024a18730b".into(), + view: "045da65316a906a8c30046053119c18020b07a7a3a6ef5c01ab2a8755416bd02".into(), + }, + ]; + + for vector in vectors { + let trim_seed = |seed: &str| { + seed + .split_whitespace() + .map(|word| trim_by_lang(word, vector.language)) + .collect::>() + .join(" ") + }; + + // Test against Monero + { + let seed = Seed::from_string(Zeroizing::new(vector.seed.clone())).unwrap(); + assert_eq!(seed, Seed::from_string(Zeroizing::new(trim_seed(&vector.seed))).unwrap()); + + let spend: [u8; 32] = hex::decode(vector.spend).unwrap().try_into().unwrap(); + // For classical seeds, Monero directly uses the entropy as a spend key + assert_eq!( + Scalar::from_canonical_bytes(*seed.entropy()), + Scalar::from_canonical_bytes(spend) + ); + + let view: [u8; 32] = hex::decode(vector.view).unwrap().try_into().unwrap(); + // Monero then derives the view key as H(spend) + assert_eq!( + Scalar::from_bytes_mod_order(hash(&spend)), + Scalar::from_canonical_bytes(view).unwrap() + ); + + assert_eq!(Seed::from_entropy(vector.language, Zeroizing::new(spend)).unwrap(), seed); + } + + // Test against ourself + { + let seed = Seed::new(&mut OsRng, vector.language); + assert_eq!(seed, Seed::from_string(Zeroizing::new(trim_seed(&seed.to_string()))).unwrap()); + assert_eq!(seed, Seed::from_entropy(vector.language, seed.entropy()).unwrap()); + assert_eq!(seed, Seed::from_string(seed.to_string()).unwrap()); + } + } +} diff --git a/coins/monero/src/transaction.rs b/coins/monero/src/transaction.rs index 6314a97c..e981792a 100644 --- a/coins/monero/src/transaction.rs +++ b/coins/monero/src/transaction.rs @@ -1,4 +1,5 @@ use core::cmp::Ordering; +use std::io::{self, Read, Write}; use zeroize::Zeroize; @@ -27,7 +28,7 @@ impl Input { 1 + 1 + 1 + (8 * ring_len) + 32 } - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { + pub fn write(&self, w: &mut W) -> io::Result<()> { match self { Input::Gen(height) => { w.write_all(&[255])?; @@ -43,7 +44,7 @@ impl Input { } } - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn read(r: &mut R) -> io::Result { Ok(match read_byte(r)? { 255 => Input::Gen(read_varint(r)?), 2 => Input::ToKey { @@ -51,10 +52,9 @@ impl Input { key_offsets: read_vec(read_varint, r)?, key_image: read_torsion_free_point(r)?, }, - _ => Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Tried to deserialize unknown/unused input type", - ))?, + _ => { + Err(io::Error::new(io::ErrorKind::Other, "Tried to deserialize unknown/unused input type"))? + } }) } } @@ -72,7 +72,7 @@ impl Output { 1 + 1 + 32 + 1 } - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { + pub fn write(&self, w: &mut W) -> io::Result<()> { write_varint(&self.amount, w)?; w.write_all(&[2 + u8::from(self.view_tag.is_some())])?; w.write_all(&self.key.to_bytes())?; @@ -82,13 +82,13 @@ impl Output { Ok(()) } - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn read(r: &mut R) -> io::Result { let amount = read_varint(r)?; let view_tag = match read_byte(r)? { 2 => false, 3 => true, - _ => Err(std::io::Error::new( - std::io::ErrorKind::Other, + _ => Err(io::Error::new( + io::ErrorKind::Other, "Tried to deserialize unknown/unused output type", ))?, }; @@ -119,7 +119,7 @@ impl Timelock { } } - fn serialize(&self, w: &mut W) -> std::io::Result<()> { + fn write(&self, w: &mut W) -> io::Result<()> { write_varint( &match self { Timelock::None => 0, @@ -163,21 +163,21 @@ impl TransactionPrefix { extra } - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { + pub fn write(&self, w: &mut W) -> io::Result<()> { write_varint(&self.version, w)?; - self.timelock.serialize(w)?; - write_vec(Input::serialize, &self.inputs, w)?; - write_vec(Output::serialize, &self.outputs, w)?; + self.timelock.write(w)?; + write_vec(Input::write, &self.inputs, w)?; + write_vec(Output::write, &self.outputs, w)?; write_varint(&self.extra.len().try_into().unwrap(), w)?; w.write_all(&self.extra) } - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn read(r: &mut R) -> io::Result { let mut prefix = TransactionPrefix { version: read_varint(r)?, timelock: Timelock::from_raw(read_varint(r)?), - inputs: read_vec(Input::deserialize, r)?, - outputs: read_vec(Output::deserialize, r)?, + inputs: read_vec(Input::read, r)?, + outputs: read_vec(Output::read, r)?, extra: vec![], }; prefix.extra = read_vec(read_byte, r)?; @@ -204,8 +204,8 @@ impl Transaction { RctSignatures::fee_weight(protocol, inputs, outputs) } - pub fn serialize(&self, w: &mut W) -> std::io::Result<()> { - self.prefix.serialize(w)?; + pub fn write(&self, w: &mut W) -> io::Result<()> { + self.prefix.write(w)?; if self.prefix.version == 1 { for sig in &self.signatures { write_scalar(&sig.0, w)?; @@ -213,14 +213,14 @@ impl Transaction { } Ok(()) } else if self.prefix.version == 2 { - self.rct_signatures.serialize(w) + self.rct_signatures.write(w) } else { panic!("Serializing a transaction with an unknown version"); } } - pub fn deserialize(r: &mut R) -> std::io::Result { - let prefix = TransactionPrefix::deserialize(r)?; + pub fn read(r: &mut R) -> io::Result { + let prefix = TransactionPrefix::read(r)?; let mut signatures = vec![]; let mut rct_signatures = RctSignatures { base: RctBase { fee: 0, ecdh_info: vec![], commitments: vec![] }, @@ -241,7 +241,7 @@ impl Transaction { .sum::() .saturating_sub(prefix.outputs.iter().map(|output| output.amount).sum()); } else if prefix.version == 2 { - rct_signatures = RctSignatures::deserialize( + rct_signatures = RctSignatures::read( prefix .inputs .iter() @@ -254,64 +254,56 @@ impl Transaction { r, )?; } else { - Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown version"))?; + Err(io::Error::new(io::ErrorKind::Other, "Tried to deserialize unknown version"))?; } Ok(Transaction { prefix, signatures, rct_signatures }) } pub fn hash(&self) -> [u8; 32] { - let mut serialized = Vec::with_capacity(2048); + let mut buf = Vec::with_capacity(2048); if self.prefix.version == 1 { - self.serialize(&mut serialized).unwrap(); - hash(&serialized) + self.write(&mut buf).unwrap(); + hash(&buf) } else { - let mut sig_hash = Vec::with_capacity(96); + let mut hashes = Vec::with_capacity(96); - self.prefix.serialize(&mut serialized).unwrap(); - sig_hash.extend(hash(&serialized)); - serialized.clear(); + self.prefix.write(&mut buf).unwrap(); + hashes.extend(hash(&buf)); + buf.clear(); - self - .rct_signatures - .base - .serialize(&mut serialized, self.rct_signatures.prunable.rct_type()) - .unwrap(); - sig_hash.extend(hash(&serialized)); - serialized.clear(); + self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap(); + hashes.extend(hash(&buf)); + buf.clear(); match self.rct_signatures.prunable { - RctPrunable::Null => serialized.resize(32, 0), + RctPrunable::Null => buf.resize(32, 0), _ => { - self.rct_signatures.prunable.serialize(&mut serialized).unwrap(); - serialized = hash(&serialized).to_vec(); + self.rct_signatures.prunable.write(&mut buf).unwrap(); + buf = hash(&buf).to_vec(); } } - sig_hash.extend(&serialized); + hashes.extend(&buf); - hash(&sig_hash) + hash(&hashes) } } /// Calculate the hash of this transaction as needed for signing it. pub fn signature_hash(&self) -> [u8; 32] { - let mut serialized = Vec::with_capacity(2048); + let mut buf = Vec::with_capacity(2048); let mut sig_hash = Vec::with_capacity(96); - self.prefix.serialize(&mut serialized).unwrap(); - sig_hash.extend(hash(&serialized)); - serialized.clear(); + self.prefix.write(&mut buf).unwrap(); + sig_hash.extend(hash(&buf)); + buf.clear(); - self - .rct_signatures - .base - .serialize(&mut serialized, self.rct_signatures.prunable.rct_type()) - .unwrap(); - sig_hash.extend(hash(&serialized)); - serialized.clear(); + self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap(); + sig_hash.extend(hash(&buf)); + buf.clear(); - self.rct_signatures.prunable.signature_serialize(&mut serialized).unwrap(); - sig_hash.extend(hash(&serialized)); + self.rct_signatures.prunable.signature_write(&mut buf).unwrap(); + sig_hash.extend(hash(&buf)); hash(&sig_hash) } diff --git a/coins/monero/src/wallet/address.rs b/coins/monero/src/wallet/address.rs index 063c7e6f..9a232d2a 100644 --- a/coins/monero/src/wallet/address.rs +++ b/coins/monero/src/wallet/address.rs @@ -24,26 +24,59 @@ pub enum AddressType { Standard, Integrated([u8; 8]), Subaddress, - Featured(bool, Option<[u8; 8]>, bool), + Featured { subaddress: bool, payment_id: Option<[u8; 8]>, guaranteed: bool }, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] +pub struct SubaddressIndex { + pub(crate) account: u32, + pub(crate) address: u32, +} + +impl SubaddressIndex { + pub const fn new(account: u32, address: u32) -> Option { + if (account == 0) && (address == 0) { + return None; + } + Some(SubaddressIndex { account, address }) + } + + pub fn account(&self) -> u32 { + self.account + } + + pub fn address(&self) -> u32 { + self.address + } +} + +/// Address specification. Used internally to create addresses. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] +pub enum AddressSpec { + Standard, + Integrated([u8; 8]), + Subaddress(SubaddressIndex), + Featured { subaddress: Option, payment_id: Option<[u8; 8]>, guaranteed: bool }, } impl AddressType { - pub fn subaddress(&self) -> bool { - matches!(self, AddressType::Subaddress) || matches!(self, AddressType::Featured(true, ..)) + pub fn is_subaddress(&self) -> bool { + matches!(self, AddressType::Subaddress) || + matches!(self, AddressType::Featured { subaddress: true, .. }) } pub fn payment_id(&self) -> Option<[u8; 8]> { if let AddressType::Integrated(id) = self { Some(*id) - } else if let AddressType::Featured(_, id, _) = self { - *id + } else if let AddressType::Featured { payment_id, .. } = self { + *payment_id } else { None } } - pub fn guaranteed(&self) -> bool { - matches!(self, AddressType::Featured(_, _, true)) + pub fn is_guaranteed(&self) -> bool { + matches!(self, AddressType::Featured { guaranteed: true, .. }) } } @@ -105,7 +138,7 @@ impl AddressMeta { AddressType::Standard => bytes.0, AddressType::Integrated(_) => bytes.1, AddressType::Subaddress => bytes.2, - AddressType::Featured(..) => bytes.3, + AddressType::Featured { .. } => bytes.3, } } @@ -114,7 +147,7 @@ impl AddressMeta { AddressMeta { _bytes: PhantomData, network, kind } } - // Returns an incomplete type in the case of Integrated/Featured addresses + // Returns an incomplete instantiation in the case of Integrated/Featured addresses fn from_byte(byte: u8) -> Result { let mut meta = None; for network in [Network::Mainnet, Network::Testnet, Network::Stagenet] { @@ -123,7 +156,9 @@ impl AddressMeta { _ if byte == standard => Some(AddressType::Standard), _ if byte == integrated => Some(AddressType::Integrated([0; 8])), _ if byte == subaddress => Some(AddressType::Subaddress), - _ if byte == featured => Some(AddressType::Featured(false, None, false)), + _ if byte == featured => { + Some(AddressType::Featured { subaddress: false, payment_id: None, guaranteed: false }) + } _ => None, } { meta = Some(AddressMeta::new(network, kind)); @@ -134,16 +169,16 @@ impl AddressMeta { meta.ok_or(AddressError::InvalidByte) } - pub fn subaddress(&self) -> bool { - self.kind.subaddress() + pub fn is_subaddress(&self) -> bool { + self.kind.is_subaddress() } pub fn payment_id(&self) -> Option<[u8; 8]> { self.kind.payment_id() } - pub fn guaranteed(&self) -> bool { - self.kind.guaranteed() + pub fn is_guaranteed(&self) -> bool { + self.kind.is_guaranteed() } } @@ -168,7 +203,7 @@ impl ToString for Address { let mut data = vec![self.meta.to_byte()]; data.extend(self.spend.compress().to_bytes()); data.extend(self.view.compress().to_bytes()); - if let AddressType::Featured(subaddress, payment_id, guaranteed) = self.meta.kind { + if let AddressType::Featured { subaddress, payment_id, guaranteed } = self.meta.kind { // Technically should be a VarInt, yet we don't have enough features it's needed data.push( u8::from(subaddress) + (u8::from(payment_id.is_some()) << 1) + (u8::from(guaranteed) << 2), @@ -201,7 +236,7 @@ impl Address { .ok_or(AddressError::InvalidKey)?; let mut read = 65; - if matches!(meta.kind, AddressType::Featured(..)) { + if matches!(meta.kind, AddressType::Featured { .. }) { if raw[read] >= (2 << 3) { Err(AddressError::UnknownFeatures)?; } @@ -210,8 +245,11 @@ impl Address { let integrated = ((raw[read] >> 1) & 1) == 1; let guaranteed = ((raw[read] >> 2) & 1) == 1; - meta.kind = - AddressType::Featured(subaddress, Some([0; 8]).filter(|_| integrated), guaranteed); + meta.kind = AddressType::Featured { + subaddress, + payment_id: Some([0; 8]).filter(|_| integrated), + guaranteed, + }; read += 1; } @@ -226,7 +264,7 @@ impl Address { if let AddressType::Integrated(ref mut id) = meta.kind { id.copy_from_slice(&raw[(read - 8) .. read]); } - if let AddressType::Featured(_, Some(ref mut id), _) = meta.kind { + if let AddressType::Featured { payment_id: Some(ref mut id), .. } = meta.kind { id.copy_from_slice(&raw[(read - 8) .. read]); } @@ -247,16 +285,16 @@ impl Address { self.meta.network } - pub fn subaddress(&self) -> bool { - self.meta.subaddress() + pub fn is_subaddress(&self) -> bool { + self.meta.is_subaddress() } pub fn payment_id(&self) -> Option<[u8; 8]> { self.meta.payment_id() } - pub fn guaranteed(&self) -> bool { - self.meta.guaranteed() + pub fn is_guaranteed(&self) -> bool { + self.meta.is_guaranteed() } } diff --git a/coins/monero/src/wallet/decoys.rs b/coins/monero/src/wallet/decoys.rs index a0dd32bd..4b67955a 100644 --- a/coins/monero/src/wallet/decoys.rs +++ b/coins/monero/src/wallet/decoys.rs @@ -1,4 +1,6 @@ -use std::{sync::Mutex, collections::HashSet}; +use std::collections::HashSet; + +use futures::lock::{Mutex, MutexGuard}; use lazy_static::lazy_static; @@ -23,13 +25,16 @@ const TIP_APPLICATION: f64 = (LOCK_WINDOW * BLOCK_TIME) as f64; lazy_static! { static ref GAMMA: Gamma = Gamma::new(19.28, 1.0 / 1.61).unwrap(); + // TODO: Expose an API to reset this in case a reorg occurs/the RPC fails/returns garbage + // TODO: Update this when scanning a block, as possible static ref DISTRIBUTION: Mutex> = Mutex::new(Vec::with_capacity(3000000)); } #[allow(clippy::too_many_arguments)] -async fn select_n( +async fn select_n<'a, R: RngCore + CryptoRng>( rng: &mut R, rpc: &Rpc, + distribution: &MutexGuard<'a, Vec>, height: usize, high: u64, per_second: f64, @@ -61,7 +66,6 @@ async fn select_n( let o = (age * per_second) as u64; if o < high { - let distribution = DISTRIBUTION.lock().unwrap(); let i = distribution.partition_point(|s| *s < (high - 1 - o)); let prev = i.saturating_sub(1); let n = distribution[i] - distribution[prev]; @@ -136,6 +140,8 @@ impl Decoys { height: usize, inputs: &[SpendableOutput], ) -> Result, RpcError> { + let mut distribution = DISTRIBUTION.lock().await; + let decoy_count = ring_len - 1; // Convert the inputs in question to the raw output data @@ -146,29 +152,19 @@ impl Decoys { outputs.push((real[real.len() - 1], [input.key(), input.commitment().calculate()])); } - let distribution_len = { - let distribution = DISTRIBUTION.lock().unwrap(); - distribution.len() - }; - if distribution_len <= height { - let extension = rpc.get_output_distribution(distribution_len, height).await?; - DISTRIBUTION.lock().unwrap().extend(extension); + if distribution.len() <= height { + let extension = rpc.get_output_distribution(distribution.len(), height).await?; + distribution.extend(extension); } + // If asked to use an older height than previously asked, truncate to ensure accuracy + // Should never happen, yet risks desyncing if it did + distribution.truncate(height + 1); // height is inclusive, and 0 is a valid height - let high; - let per_second; - { - let mut distribution = DISTRIBUTION.lock().unwrap(); - // If asked to use an older height than previously asked, truncate to ensure accuracy - // Should never happen, yet risks desyncing if it did - distribution.truncate(height + 1); // height is inclusive, and 0 is a valid height - - high = distribution[distribution.len() - 1]; - per_second = { - let blocks = distribution.len().min(BLOCKS_PER_YEAR); - let outputs = high - distribution[distribution.len().saturating_sub(blocks + 1)]; - (outputs as f64) / ((blocks * BLOCK_TIME) as f64) - }; + let high = distribution[distribution.len() - 1]; + let per_second = { + let blocks = distribution.len().min(BLOCKS_PER_YEAR); + let outputs = high - distribution[distribution.len().saturating_sub(blocks + 1)]; + (outputs as f64) / ((blocks * BLOCK_TIME) as f64) }; let mut used = HashSet::::new(); @@ -184,9 +180,18 @@ impl Decoys { // Select all decoys for this transaction, assuming we generate a sane transaction // We should almost never naturally generate an insane transaction, hence why this doesn't // bother with an overage - let mut decoys = - select_n(rng, rpc, height, high, per_second, &real, &mut used, inputs.len() * decoy_count) - .await?; + let mut decoys = select_n( + rng, + rpc, + &distribution, + height, + high, + per_second, + &real, + &mut used, + inputs.len() * decoy_count, + ) + .await?; real.zeroize(); let mut res = Vec::with_capacity(inputs.len()); @@ -224,8 +229,18 @@ impl Decoys { // Select new outputs until we have a full sized ring again ring.extend( - select_n(rng, rpc, height, high, per_second, &[], &mut used, ring_len - ring.len()) - .await?, + select_n( + rng, + rpc, + &distribution, + height, + high, + per_second, + &[], + &mut used, + ring_len - ring.len(), + ) + .await?, ); ring.sort_by(|a, b| a.0.cmp(&b.0)); } diff --git a/coins/monero/src/wallet/extra.rs b/coins/monero/src/wallet/extra.rs index ac8924a4..1b902109 100644 --- a/coins/monero/src/wallet/extra.rs +++ b/coins/monero/src/wallet/extra.rs @@ -1,5 +1,5 @@ use core::ops::BitXor; -use std::io::{self, Read, Write, Cursor}; +use std::io::{self, Read, Write}; use zeroize::Zeroize; @@ -12,8 +12,16 @@ use crate::serialize::{ pub const MAX_TX_EXTRA_NONCE_SIZE: usize = 255; +pub const PAYMENT_ID_MARKER: u8 = 0; +pub const ENCRYPTED_PAYMENT_ID_MARKER: u8 = 1; +// Used as it's the highest value not interpretable as a continued VarInt +pub const ARBITRARY_DATA_MARKER: u8 = 127; + +// 1 byte is used for the marker +pub const MAX_ARBITRARY_DATA_SIZE: usize = MAX_TX_EXTRA_NONCE_SIZE - 1; + #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] -pub(crate) enum PaymentId { +pub enum PaymentId { Unencrypted([u8; 32]), Encrypted([u8; 8]), } @@ -23,6 +31,7 @@ impl BitXor<[u8; 8]> for PaymentId { fn bitxor(self, bytes: [u8; 8]) -> PaymentId { match self { + // Don't perform the xor since this isn't intended to be encrypted with xor PaymentId::Unencrypted(_) => self, PaymentId::Encrypted(id) => { PaymentId::Encrypted((u64::from_le_bytes(id) ^ u64::from_le_bytes(bytes)).to_le_bytes()) @@ -32,21 +41,21 @@ impl BitXor<[u8; 8]> for PaymentId { } impl PaymentId { - pub(crate) fn serialize(&self, w: &mut W) -> io::Result<()> { + pub fn write(&self, w: &mut W) -> io::Result<()> { match self { PaymentId::Unencrypted(id) => { - w.write_all(&[0])?; + w.write_all(&[PAYMENT_ID_MARKER])?; w.write_all(id)?; } PaymentId::Encrypted(id) => { - w.write_all(&[1])?; + w.write_all(&[ENCRYPTED_PAYMENT_ID_MARKER])?; w.write_all(id)?; } } Ok(()) } - fn deserialize(r: &mut R) -> io::Result { + pub fn read(r: &mut R) -> io::Result { Ok(match read_byte(r)? { 0 => PaymentId::Unencrypted(read_bytes(r)?), 1 => PaymentId::Encrypted(read_bytes(r)?), @@ -57,7 +66,7 @@ impl PaymentId { // Doesn't bother with padding nor MinerGate #[derive(Clone, PartialEq, Eq, Debug, Zeroize)] -pub(crate) enum ExtraField { +pub enum ExtraField { PublicKey(EdwardsPoint), Nonce(Vec), MergeMining(usize, [u8; 32]), @@ -65,7 +74,7 @@ pub(crate) enum ExtraField { } impl ExtraField { - fn serialize(&self, w: &mut W) -> io::Result<()> { + pub fn write(&self, w: &mut W) -> io::Result<()> { match self { ExtraField::PublicKey(key) => { w.write_all(&[1])?; @@ -88,7 +97,7 @@ impl ExtraField { Ok(()) } - fn deserialize(r: &mut R) -> io::Result { + pub fn read(r: &mut R) -> io::Result { Ok(match read_byte(r)? { 1 => ExtraField::PublicKey(read_point(r)?), 2 => ExtraField::Nonce({ @@ -110,52 +119,50 @@ impl ExtraField { } #[derive(Clone, PartialEq, Eq, Debug, Zeroize)] -pub(crate) struct Extra(Vec); +pub struct Extra(Vec); impl Extra { - pub(crate) fn keys(&self) -> Vec { - let mut keys = Vec::with_capacity(2); + pub fn keys(&self) -> Option<(EdwardsPoint, Option>)> { + let mut key = None; + let mut additional = None; for field in &self.0 { match field.clone() { - ExtraField::PublicKey(key) => keys.push(key), - ExtraField::PublicKeys(additional) => keys.extend(additional), + ExtraField::PublicKey(this_key) => key = key.or(Some(this_key)), + ExtraField::PublicKeys(these_additional) => { + additional = additional.or(Some(these_additional)) + } _ => (), } } - keys + // Don't return any keys if this was non-standard and didn't include the primary key + key.map(|key| (key, additional)) } - pub(crate) fn payment_id(&self) -> Option { + pub fn payment_id(&self) -> Option { for field in &self.0 { if let ExtraField::Nonce(data) = field { - return PaymentId::deserialize(&mut Cursor::new(data)).ok(); + return PaymentId::read::<&[u8]>(&mut data.as_ref()).ok(); } } None } - pub(crate) fn data(&self) -> Vec> { - let mut first = true; + pub fn data(&self) -> Vec> { let mut res = vec![]; for field in &self.0 { if let ExtraField::Nonce(data) = field { - // Skip the first Nonce, which should be the payment ID - if first { - first = false; - continue; + if data[0] == ARBITRARY_DATA_MARKER { + res.push(data[1 ..].to_vec()); } - res.push(data.clone()); } } res } - pub(crate) fn new(mut keys: Vec) -> Extra { + pub(crate) fn new(key: EdwardsPoint, additional: Vec) -> Extra { let mut res = Extra(Vec::with_capacity(3)); - if !keys.is_empty() { - res.push(ExtraField::PublicKey(keys[0])); - } - if keys.len() > 1 { - res.push(ExtraField::PublicKeys(keys.drain(1 ..).collect())); + res.push(ExtraField::PublicKey(key)); + if !additional.is_empty() { + res.push(ExtraField::PublicKeys(additional)); } res } @@ -165,29 +172,35 @@ impl Extra { } #[rustfmt::skip] - pub(crate) fn fee_weight(outputs: usize, data: &[Vec]) -> usize { + pub(crate) fn fee_weight(outputs: usize, payment_id: bool, data: &[Vec]) -> usize { // PublicKey, key (1 + 32) + // PublicKeys, length, additional keys (1 + 1 + (outputs.saturating_sub(1) * 32)) + // PaymentId (Nonce), length, encrypted, ID - (1 + 1 + 1 + 8) + + (if payment_id { 1 + 1 + 1 + 8 } else { 0 }) + // Nonce, length, data (if existent) data.iter().map(|v| 1 + varint_len(v.len()) + v.len()).sum::() } - pub(crate) fn serialize(&self, w: &mut W) -> io::Result<()> { + pub fn write(&self, w: &mut W) -> io::Result<()> { for field in &self.0 { - field.serialize(w)?; + field.write(w)?; } Ok(()) } - pub(crate) fn deserialize(r: &mut R) -> io::Result { + pub fn serialize(&self) -> Vec { + let mut buf = vec![]; + self.write(&mut buf).unwrap(); + buf + } + + pub fn read(r: &mut R) -> io::Result { let mut res = Extra(vec![]); let mut field; while { - field = ExtraField::deserialize(r); + field = ExtraField::read(r); field.is_ok() } { res.0.push(field.unwrap()); diff --git a/coins/monero/src/wallet/mod.rs b/coins/monero/src/wallet/mod.rs index 5b776d2d..d7dff8ff 100644 --- a/coins/monero/src/wallet/mod.rs +++ b/coins/monero/src/wallet/mod.rs @@ -11,21 +11,26 @@ use curve25519_dalek::{ use crate::{hash, hash_to_scalar, serialize::write_varint, transaction::Input}; -mod extra; +pub mod extra; pub(crate) use extra::{PaymentId, ExtraField, Extra}; +/// Seed creation and parsing functionality. +pub mod seed; + /// Address encoding and decoding functionality. pub mod address; -use address::{Network, AddressType, AddressMeta, MoneroAddress}; +use address::{Network, AddressType, SubaddressIndex, AddressSpec, AddressMeta, MoneroAddress}; mod scan; -pub use scan::{ReceivedOutput, SpendableOutput}; +pub use scan::{ReceivedOutput, SpendableOutput, Timelocked}; pub(crate) mod decoys; pub(crate) use decoys::Decoys; mod send; -pub use send::{Fee, TransactionError, SignableTransaction, SignableTransactionBuilder}; +pub use send::{Fee, TransactionError, Change, SignableTransaction, SignableTransactionBuilder}; +#[cfg(feature = "multisig")] +pub(crate) use send::InternalPayment; #[cfg(feature = "multisig")] pub use send::TransactionMachine; @@ -54,19 +59,20 @@ pub(crate) fn uniqueness(inputs: &[Input]) -> [u8; 32] { #[allow(non_snake_case)] pub(crate) fn shared_key( uniqueness: Option<[u8; 32]>, - s: &Scalar, - P: &EdwardsPoint, + ecdh: EdwardsPoint, o: usize, ) -> (u8, Scalar, [u8; 8]) { // 8Ra - let mut output_derivation = (s * P).mul_by_cofactor().compress().to_bytes().to_vec(); + let mut output_derivation = ecdh.mul_by_cofactor().compress().to_bytes().to_vec(); + + let mut payment_id_xor = [0; 8]; + payment_id_xor + .copy_from_slice(&hash(&[output_derivation.as_ref(), [0x8d].as_ref()].concat())[.. 8]); + // || o write_varint(&o.try_into().unwrap(), &mut output_derivation).unwrap(); let view_tag = hash(&[b"view_tag".as_ref(), &output_derivation].concat())[0]; - let mut payment_id_xor = [0; 8]; - payment_id_xor - .copy_from_slice(&hash(&[output_derivation.as_ref(), [0x8d].as_ref()].concat())[.. 8]); // uniqueness || let shared_key = if let Some(uniqueness) = uniqueness { @@ -106,21 +112,61 @@ impl ViewPair { ViewPair { spend, view } } - pub(crate) fn subaddress(&self, index: (u32, u32)) -> Scalar { - if index == (0, 0) { - return Scalar::zero(); - } + pub fn spend(&self) -> EdwardsPoint { + self.spend + } + pub fn view(&self) -> EdwardsPoint { + self.view.deref() * &ED25519_BASEPOINT_TABLE + } + + fn subaddress_derivation(&self, index: SubaddressIndex) -> Scalar { hash_to_scalar(&Zeroizing::new( [ b"SubAddr\0".as_ref(), Zeroizing::new(self.view.to_bytes()).as_ref(), - &index.0.to_le_bytes(), - &index.1.to_le_bytes(), + &index.account().to_le_bytes(), + &index.address().to_le_bytes(), ] .concat(), )) } + + fn subaddress_keys(&self, index: SubaddressIndex) -> (EdwardsPoint, EdwardsPoint) { + let scalar = self.subaddress_derivation(index); + let spend = self.spend + (&scalar * &ED25519_BASEPOINT_TABLE); + let view = self.view.deref() * spend; + (spend, view) + } + + /// Returns an address with the provided specification. + pub fn address(&self, network: Network, spec: AddressSpec) -> MoneroAddress { + let mut spend = self.spend; + let mut view: EdwardsPoint = self.view.deref() * &ED25519_BASEPOINT_TABLE; + + // construct the address meta + let meta = match spec { + AddressSpec::Standard => AddressMeta::new(network, AddressType::Standard), + AddressSpec::Integrated(payment_id) => { + AddressMeta::new(network, AddressType::Integrated(payment_id)) + } + AddressSpec::Subaddress(index) => { + (spend, view) = self.subaddress_keys(index); + AddressMeta::new(network, AddressType::Subaddress) + } + AddressSpec::Featured { subaddress, payment_id, guaranteed } => { + if let Some(index) = subaddress { + (spend, view) = self.subaddress_keys(index); + } + AddressMeta::new( + network, + AddressType::Featured { subaddress: subaddress.is_some(), payment_id, guaranteed }, + ) + } + }; + + MoneroAddress::new(meta, spend, view) + } } /// Transaction scanner. @@ -130,15 +176,14 @@ impl ViewPair { #[derive(Clone)] pub struct Scanner { pair: ViewPair, - network: Network, - pub(crate) subaddresses: HashMap, + // Also contains the spend key as None + pub(crate) subaddresses: HashMap>, pub(crate) burning_bug: Option>, } impl Zeroize for Scanner { fn zeroize(&mut self) { self.pair.zeroize(); - self.network.zeroize(); // These may not be effective, unfortunately for (mut key, mut value) in self.subaddresses.drain() { @@ -163,59 +208,24 @@ impl ZeroizeOnDrop for Scanner {} impl Scanner { /// Create a Scanner from a ViewPair. - /// The network is used for generating subaddresses. /// burning_bug is a HashSet of used keys, intended to prevent key reuse which would burn funds. /// When an output is successfully scanned, the output key MUST be saved to disk. /// When a new scanner is created, ALL saved output keys must be passed in to be secure. /// If None is passed, a modified shared key derivation is used which is immune to the burning /// bug (specifically the Guaranteed feature from Featured Addresses). - // TODO: Should this take in a DB access handle to ensure output keys are saved? - pub fn from_view( - pair: ViewPair, - network: Network, - burning_bug: Option>, - ) -> Scanner { + pub fn from_view(pair: ViewPair, burning_bug: Option>) -> Scanner { let mut subaddresses = HashMap::new(); - subaddresses.insert(pair.spend.compress(), (0, 0)); - Scanner { pair, network, subaddresses, burning_bug } + subaddresses.insert(pair.spend.compress(), None); + Scanner { pair, subaddresses, burning_bug } } - /// Return the main address for this view pair. - pub fn address(&self) -> MoneroAddress { - MoneroAddress::new( - AddressMeta::new( - self.network, - if self.burning_bug.is_none() { - AddressType::Featured(false, None, true) - } else { - AddressType::Standard - }, - ), - self.pair.spend, - self.pair.view.deref() * &ED25519_BASEPOINT_TABLE, - ) - } - - /// Return the specified subaddress for this view pair. - pub fn subaddress(&mut self, index: (u32, u32)) -> MoneroAddress { - if index == (0, 0) { - return self.address(); - } - - let spend = self.pair.spend + (&self.pair.subaddress(index) * &ED25519_BASEPOINT_TABLE); - self.subaddresses.insert(spend.compress(), index); - - MoneroAddress::new( - AddressMeta::new( - self.network, - if self.burning_bug.is_none() { - AddressType::Featured(true, None, true) - } else { - AddressType::Subaddress - }, - ), - spend, - self.pair.view.deref() * spend, - ) + /// Register a subaddress. + // There used to be an address function here, yet it wasn't safe. It could generate addresses + // incompatible with the Scanner. While we could return None for that, then we have the issue + // of runtime failures to generate an address. + // Removing that API was the simplest option. + pub fn register_subaddress(&mut self, subaddress: SubaddressIndex) { + let (spend, _) = self.pair.subaddress_keys(subaddress); + self.subaddresses.insert(spend.compress(), Some(subaddress)); } } diff --git a/coins/monero/src/wallet/scan.rs b/coins/monero/src/wallet/scan.rs index 2dff5ed5..3deb080f 100644 --- a/coins/monero/src/wallet/scan.rs +++ b/coins/monero/src/wallet/scan.rs @@ -1,4 +1,5 @@ -use std::io::Cursor; +use core::ops::Deref; +use std::io::{self, Read, Write}; use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -10,7 +11,10 @@ use crate::{ transaction::{Input, Timelock, Transaction}, block::Block, rpc::{Rpc, RpcError}, - wallet::{PaymentId, Extra, Scanner, uniqueness, shared_key, amount_decryption, commitment_mask}, + wallet::{ + PaymentId, Extra, address::SubaddressIndex, Scanner, uniqueness, shared_key, amount_decryption, + commitment_mask, + }, }; /// An absolute output ID, defined as its transaction hash and output index. @@ -21,14 +25,18 @@ pub struct AbsoluteId { } impl AbsoluteId { - pub fn serialize(&self) -> Vec { - let mut res = Vec::with_capacity(32 + 1); - res.extend(self.tx); - res.push(self.o); - res + pub fn write(&self, w: &mut W) -> io::Result<()> { + w.write_all(&self.tx)?; + w.write_all(&[self.o]) } - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn serialize(&self) -> Vec { + let mut serialized = Vec::with_capacity(32 + 1); + self.write(&mut serialized).unwrap(); + serialized + } + + pub fn read(r: &mut R) -> io::Result { Ok(AbsoluteId { tx: read_bytes(r)?, o: read_byte(r)? }) } } @@ -43,16 +51,20 @@ pub struct OutputData { } impl OutputData { - pub fn serialize(&self) -> Vec { - let mut res = Vec::with_capacity(32 + 32 + 40); - res.extend(self.key.compress().to_bytes()); - res.extend(self.key_offset.to_bytes()); - res.extend(self.commitment.mask.to_bytes()); - res.extend(self.commitment.amount.to_le_bytes()); - res + pub fn write(&self, w: &mut W) -> io::Result<()> { + w.write_all(&self.key.compress().to_bytes())?; + w.write_all(&self.key_offset.to_bytes())?; + w.write_all(&self.commitment.mask.to_bytes())?; + w.write_all(&self.commitment.amount.to_le_bytes()) } - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn serialize(&self) -> Vec { + let mut serialized = Vec::with_capacity(32 + 32 + 32 + 8); + self.write(&mut serialized).unwrap(); + serialized + } + + pub fn read(r: &mut R) -> io::Result { Ok(OutputData { key: read_point(r)?, key_offset: read_scalar(r)?, @@ -64,9 +76,8 @@ impl OutputData { /// The metadata for an output. #[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)] pub struct Metadata { - // Does not have to be an Option since the 0 subaddress is the main address /// The subaddress this output was sent to. - pub subaddress: (u32, u32), + pub subaddress: Option, /// The payment ID included with this output. /// This will be gibberish if the payment ID wasn't intended for the recipient or wasn't included. // Could be an Option, as extra doesn't necessarily have a payment ID, yet all Monero TXs should @@ -77,23 +88,42 @@ pub struct Metadata { } impl Metadata { - pub fn serialize(&self) -> Vec { - let mut res = Vec::with_capacity(4 + 4 + 8 + 1); - res.extend(self.subaddress.0.to_le_bytes()); - res.extend(self.subaddress.1.to_le_bytes()); - res.extend(self.payment_id); - - res.extend(u32::try_from(self.arbitrary_data.len()).unwrap().to_le_bytes()); - for part in &self.arbitrary_data { - res.extend([u8::try_from(part.len()).unwrap()]); - res.extend(part); + pub fn write(&self, w: &mut W) -> io::Result<()> { + if let Some(subaddress) = self.subaddress { + w.write_all(&[1])?; + w.write_all(&subaddress.account().to_le_bytes())?; + w.write_all(&subaddress.address().to_le_bytes())?; + } else { + w.write_all(&[0])?; } - res + w.write_all(&self.payment_id)?; + + w.write_all(&u32::try_from(self.arbitrary_data.len()).unwrap().to_le_bytes())?; + for part in &self.arbitrary_data { + w.write_all(&[u8::try_from(part.len()).unwrap()])?; + w.write_all(part)?; + } + Ok(()) } - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn serialize(&self) -> Vec { + let mut serialized = Vec::with_capacity(1 + 8 + 1); + self.write(&mut serialized).unwrap(); + serialized + } + + pub fn read(r: &mut R) -> io::Result { + let subaddress = if read_byte(r)? == 1 { + Some( + SubaddressIndex::new(read_u32(r)?, read_u32(r)?) + .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid subaddress in metadata"))?, + ) + } else { + None + }; + Ok(Metadata { - subaddress: (read_u32(r)?, read_u32(r)?), + subaddress, payment_id: read_bytes(r)?, arbitrary_data: { let mut data = vec![]; @@ -132,18 +162,23 @@ impl ReceivedOutput { &self.metadata.arbitrary_data } + pub fn write(&self, w: &mut W) -> io::Result<()> { + self.absolute.write(w)?; + self.data.write(w)?; + self.metadata.write(w) + } + pub fn serialize(&self) -> Vec { - let mut serialized = self.absolute.serialize(); - serialized.extend(&self.data.serialize()); - serialized.extend(&self.metadata.serialize()); + let mut serialized = vec![]; + self.write(&mut serialized).unwrap(); serialized } - pub fn deserialize(r: &mut R) -> std::io::Result { + pub fn read(r: &mut R) -> io::Result { Ok(ReceivedOutput { - absolute: AbsoluteId::deserialize(r)?, - data: OutputData::deserialize(r)?, - metadata: Metadata::deserialize(r)?, + absolute: AbsoluteId::read(r)?, + data: OutputData::read(r)?, + metadata: Metadata::read(r)?, }) } } @@ -184,14 +219,19 @@ impl SpendableOutput { self.output.commitment() } + pub fn write(&self, w: &mut W) -> io::Result<()> { + self.output.write(w)?; + w.write_all(&self.global_index.to_le_bytes()) + } + pub fn serialize(&self) -> Vec { - let mut serialized = self.output.serialize(); - serialized.extend(self.global_index.to_le_bytes()); + let mut serialized = vec![]; + self.write(&mut serialized).unwrap(); serialized } - pub fn deserialize(r: &mut R) -> std::io::Result { - Ok(SpendableOutput { output: ReceivedOutput::deserialize(r)?, global_index: read_u64(r)? }) + pub fn read(r: &mut R) -> io::Result { + Ok(SpendableOutput { output: ReceivedOutput::read(r)?, global_index: read_u64(r)? }) } } @@ -232,14 +272,19 @@ impl Timelocked { impl Scanner { /// Scan a transaction to discover the received outputs. pub fn scan_transaction(&mut self, tx: &Transaction) -> Timelocked { - let extra = Extra::deserialize(&mut Cursor::new(&tx.prefix.extra)); - let keys; + let extra = Extra::read::<&[u8]>(&mut tx.prefix.extra.as_ref()); let extra = if let Ok(extra) = extra { - keys = extra.keys(); extra } else { return Timelocked(tx.prefix.timelock, vec![]); }; + + let (tx_key, additional) = if let Some((tx_key, additional)) = extra.keys() { + (tx_key, additional) + } else { + return Timelocked(tx.prefix.timelock, vec![]); + }; + let payment_id = extra.payment_id(); let mut res = vec![]; @@ -257,11 +302,22 @@ impl Scanner { } let output_key = output_key.unwrap(); - for key in &keys { + for key in [Some(Some(&tx_key)), additional.as_ref().map(|additional| additional.get(o))] { + let key = if let Some(Some(key)) = key { + key + } else if let Some(None) = key { + // This is non-standard. There were additional keys, yet not one for this output + // https://github.com/monero-project/monero/ + // blob/04a1e2875d6e35e27bb21497988a6c822d319c28/ + // src/cryptonote_basic/cryptonote_format_utils.cpp#L1062 + // TODO: Should this return? Where does Monero set the trap handler for this exception? + continue; + } else { + break; + }; let (view_tag, shared_key, payment_id_xor) = shared_key( if self.burning_bug.is_none() { Some(uniqueness(&tx.prefix.inputs)) } else { None }, - &self.pair.view, - key, + self.pair.view.deref() * key, o, ); @@ -291,9 +347,12 @@ impl Scanner { // We will not have a torsioned key in our HashMap of keys, so we wouldn't identify it as // ours // If we did though, it'd enable bypassing the included burning bug protection - debug_assert!(output_key.is_torsion_free()); + assert!(output_key.is_torsion_free()); - let key_offset = shared_key + self.pair.subaddress(subaddress); + let mut key_offset = shared_key; + if let Some(subaddress) = subaddress { + key_offset += self.pair.subaddress_derivation(subaddress); + } // Since we've found an output to us, get its amount let mut commitment = Commitment::zero(); diff --git a/coins/monero/src/wallet/seed/classic.rs b/coins/monero/src/wallet/seed/classic.rs new file mode 100644 index 00000000..4c9c0073 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic.rs @@ -0,0 +1,262 @@ +use core::ops::Deref; +use std::collections::HashMap; + +use lazy_static::lazy_static; + +use zeroize::{Zeroize, Zeroizing}; +use rand_core::{RngCore, CryptoRng}; + +use crc::{Crc, CRC_32_ISO_HDLC}; + +use curve25519_dalek::scalar::Scalar; + +use crate::{ + random_scalar, + wallet::seed::{SeedError, Language}, +}; + +pub(crate) const CLASSIC_SEED_LENGTH: usize = 24; +pub(crate) const CLASSIC_SEED_LENGTH_WITH_CHECKSUM: usize = 25; + +fn trim(word: &str, len: usize) -> Zeroizing { + Zeroizing::new(word.chars().take(len).collect()) +} + +struct WordList { + word_list: Vec, + word_map: HashMap, + trimmed_word_map: HashMap, + unique_prefix_length: usize, +} + +impl WordList { + fn new(words: &'static str, prefix_length: usize) -> WordList { + let mut lang = WordList { + word_list: serde_json::from_str(words).unwrap(), + word_map: HashMap::new(), + trimmed_word_map: HashMap::new(), + unique_prefix_length: prefix_length, + }; + + for (i, word) in lang.word_list.iter().enumerate() { + lang.word_map.insert(word.clone(), i); + lang.trimmed_word_map.insert(trim(word, lang.unique_prefix_length).deref().clone(), i); + } + + lang + } +} + +lazy_static! { + static ref LANGUAGES: HashMap = HashMap::from([ + (Language::Chinese, WordList::new(include_str!("./classic/zh.json"), 1)), + (Language::English, WordList::new(include_str!("./classic/en.json"), 3)), + (Language::Dutch, WordList::new(include_str!("./classic/nl.json"), 4)), + (Language::French, WordList::new(include_str!("./classic/fr.json"), 4)), + (Language::Spanish, WordList::new(include_str!("./classic/es.json"), 4)), + (Language::German, WordList::new(include_str!("./classic/de.json"), 4)), + (Language::Italian, WordList::new(include_str!("./classic/it.json"), 4)), + (Language::Portuguese, WordList::new(include_str!("./classic/pt.json"), 4)), + (Language::Japanese, WordList::new(include_str!("./classic/ja.json"), 3)), + (Language::Russian, WordList::new(include_str!("./classic/ru.json"), 4)), + (Language::Esperanto, WordList::new(include_str!("./classic/eo.json"), 4)), + (Language::Lojban, WordList::new(include_str!("./classic/jbo.json"), 4)), + (Language::EnglishOld, WordList::new(include_str!("./classic/ang.json"), 4)), + ]); +} + +#[cfg(test)] +pub(crate) fn trim_by_lang(word: &str, lang: Language) -> String { + if lang != Language::EnglishOld { + word.chars().take(LANGUAGES[&lang].unique_prefix_length).collect() + } else { + word.to_string() + } +} + +fn checksum_index(words: &[Zeroizing], lang: &WordList) -> usize { + let mut trimmed_words = Zeroizing::new(String::new()); + for w in words { + *trimmed_words += &trim(w, lang.unique_prefix_length); + } + + let crc = Crc::::new(&CRC_32_ISO_HDLC); + let mut digest = crc.digest(); + digest.update(trimmed_words.as_bytes()); + + usize::try_from(digest.finalize()).unwrap() % words.len() +} + +// Convert a private key to a seed +fn key_to_seed(lang: Language, key: Zeroizing) -> ClassicSeed { + let bytes = Zeroizing::new(key.to_bytes()); + + // get the language words + let words = &LANGUAGES[&lang].word_list; + let list_len = u64::try_from(words.len()).unwrap(); + + // To store the found words & add the checksum word later. + let mut seed = Vec::with_capacity(25); + + // convert to words + // 4 bytes -> 3 words. 8 digits base 16 -> 3 digits base 1626 + let mut segment = [0; 4]; + let mut indices = [0; 4]; + for i in 0 .. 8 { + // convert first 4 byte to u32 & get the word indices + let start = i * 4; + // convert 4 byte to u32 + segment.copy_from_slice(&bytes[start .. (start + 4)]); + // Actually convert to a u64 so we can add without overflowing + indices[0] = u64::from(u32::from_le_bytes(segment)); + indices[1] = indices[0]; + indices[0] /= list_len; + indices[2] = indices[0] + indices[1]; + indices[0] /= list_len; + indices[3] = indices[0] + indices[2]; + + // append words to seed + for i in indices.iter().skip(1) { + let word = usize::try_from(i % list_len).unwrap(); + seed.push(Zeroizing::new(words[word].clone())); + } + } + segment.zeroize(); + indices.zeroize(); + + // create a checksum word for all languages except old english + if lang != Language::EnglishOld { + let checksum = seed[checksum_index(&seed, &LANGUAGES[&lang])].clone(); + seed.push(checksum); + } + + let mut res = Zeroizing::new(String::new()); + for (i, word) in seed.iter().enumerate() { + if i != 0 { + *res += " "; + } + *res += word; + } + ClassicSeed(res) +} + +// Convert a seed to bytes +pub(crate) fn seed_to_bytes(words: &str) -> Result<(Language, Zeroizing<[u8; 32]>), SeedError> { + // get seed words + let words = words.split_whitespace().map(|w| Zeroizing::new(w.to_string())).collect::>(); + if (words.len() != CLASSIC_SEED_LENGTH) && (words.len() != CLASSIC_SEED_LENGTH_WITH_CHECKSUM) { + panic!("invalid seed passed to seed_to_bytes"); + } + + // find the language + let (matched_indices, lang_name, lang) = (|| { + let has_checksum = words.len() == CLASSIC_SEED_LENGTH_WITH_CHECKSUM; + let mut matched_indices = Zeroizing::new(vec![]); + + // Iterate through all the languages + 'language: for (lang_name, lang) in LANGUAGES.iter() { + matched_indices.zeroize(); + matched_indices.clear(); + + let map_in_use = if has_checksum { &lang.trimmed_word_map } else { &lang.word_map }; + + // Iterate through all the words and see if they're all present + for word in &words { + let trimmed = trim(word, lang.unique_prefix_length); + let word = if has_checksum { &trimmed } else { word }; + + if let Some(index) = map_in_use.get(word.deref()) { + matched_indices.push(*index); + } else { + continue 'language; + } + } + + if has_checksum { + if lang_name == &Language::EnglishOld { + Err(SeedError::EnglishOldWithChecksum)?; + } + + // exclude the last word when calculating a checksum. + let last_word = words.last().unwrap().clone(); + let checksum = words[checksum_index(&words[.. words.len() - 1], lang)].clone(); + + // check the trimmed checksum and trimmed last word line up + if trim(&checksum, lang.unique_prefix_length) != trim(&last_word, lang.unique_prefix_length) + { + Err(SeedError::InvalidChecksum)?; + } + } + + return Ok((matched_indices, lang_name, lang)); + } + + Err(SeedError::UnknownLanguage)? + })()?; + + // convert to bytes + let mut res = Zeroizing::new([0; 32]); + let mut indices = Zeroizing::new([0; 4]); + for i in 0 .. 8 { + // read 3 indices at a time + let i3 = i * 3; + indices[1] = matched_indices[i3]; + indices[2] = matched_indices[i3 + 1]; + indices[3] = matched_indices[i3 + 2]; + + let inner = |i| { + let mut base = (lang.word_list.len() - indices[i] + indices[i + 1]) % lang.word_list.len(); + // Shift the index over + for _ in 0 .. i { + base *= lang.word_list.len(); + } + base + }; + // set the last index + indices[0] = indices[1] + inner(1) + inner(2); + if (indices[0] % lang.word_list.len()) != indices[1] { + Err(SeedError::InvalidSeed)?; + } + + let pos = i * 4; + let mut bytes = u32::try_from(indices[0]).unwrap().to_le_bytes(); + res[pos .. (pos + 4)].copy_from_slice(&bytes); + bytes.zeroize(); + } + + Ok((*lang_name, res)) +} + +#[derive(Clone, PartialEq, Eq, Zeroize)] +pub struct ClassicSeed(Zeroizing); +impl ClassicSeed { + pub(crate) fn new(rng: &mut R, lang: Language) -> ClassicSeed { + key_to_seed(lang, Zeroizing::new(random_scalar(rng))) + } + + pub fn from_string(words: Zeroizing) -> Result { + let (lang, entropy) = seed_to_bytes(&words)?; + + // Make sure this is a valid scalar + let mut scalar = Scalar::from_canonical_bytes(*entropy); + if scalar.is_none() { + Err(SeedError::InvalidSeed)?; + } + scalar.zeroize(); + + // Call from_entropy so a trimmed seed becomes a full seed + Ok(Self::from_entropy(lang, entropy).unwrap()) + } + + pub fn from_entropy(lang: Language, entropy: Zeroizing<[u8; 32]>) -> Option { + Scalar::from_canonical_bytes(*entropy).map(|scalar| key_to_seed(lang, Zeroizing::new(scalar))) + } + + pub(crate) fn to_string(&self) -> Zeroizing { + self.0.clone() + } + + pub(crate) fn entropy(&self) -> Zeroizing<[u8; 32]> { + seed_to_bytes(&self.0).unwrap().1 + } +} diff --git a/coins/monero/src/wallet/seed/classic/ang.json b/coins/monero/src/wallet/seed/classic/ang.json new file mode 100644 index 00000000..1b122b65 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/ang.json @@ -0,0 +1,1628 @@ +[ + "like", + "just", + "love", + "know", + "never", + "want", + "time", + "out", + "there", + "make", + "look", + "eye", + "down", + "only", + "think", + "heart", + "back", + "then", + "into", + "about", + "more", + "away", + "still", + "them", + "take", + "thing", + "even", + "through", + "long", + "always", + "world", + "too", + "friend", + "tell", + "try", + "hand", + "thought", + "over", + "here", + "other", + "need", + "smile", + "again", + "much", + "cry", + "been", + "night", + "ever", + "little", + "said", + "end", + "some", + "those", + "around", + "mind", + "people", + "girl", + "leave", + "dream", + "left", + "turn", + "myself", + "give", + "nothing", + "really", + "off", + "before", + "something", + "find", + "walk", + "wish", + "good", + "once", + "place", + "ask", + "stop", + "keep", + "watch", + "seem", + "everything", + "wait", + "got", + "yet", + "made", + "remember", + "start", + "alone", + "run", + "hope", + "maybe", + "believe", + "body", + "hate", + "after", + "close", + "talk", + "stand", + "own", + "each", + "hurt", + "help", + "home", + "god", + "soul", + "new", + "many", + "two", + "inside", + "should", + "true", + "first", + "fear", + "mean", + "better", + "play", + "another", + "gone", + "change", + "use", + "wonder", + "someone", + "hair", + "cold", + "open", + "best", + "any", + "behind", + "happen", + "water", + "dark", + "laugh", + "stay", + "forever", + "name", + "work", + "show", + "sky", + "break", + "came", + "deep", + "door", + "put", + "black", + "together", + "upon", + "happy", + "such", + "great", + "white", + "matter", + "fill", + "past", + "please", + "burn", + "cause", + "enough", + "touch", + "moment", + "soon", + "voice", + "scream", + "anything", + "stare", + "sound", + "red", + "everyone", + "hide", + "kiss", + "truth", + "death", + "beautiful", + "mine", + "blood", + "broken", + "very", + "pass", + "next", + "forget", + "tree", + "wrong", + "air", + "mother", + "understand", + "lip", + "hit", + "wall", + "memory", + "sleep", + "free", + "high", + "realize", + "school", + "might", + "skin", + "sweet", + "perfect", + "blue", + "kill", + "breath", + "dance", + "against", + "fly", + "between", + "grow", + "strong", + "under", + "listen", + "bring", + "sometimes", + "speak", + "pull", + "person", + "become", + "family", + "begin", + "ground", + "real", + "small", + "father", + "sure", + "feet", + "rest", + "young", + "finally", + "land", + "across", + "today", + "different", + "guy", + "line", + "fire", + "reason", + "reach", + "second", + "slowly", + "write", + "eat", + "smell", + "mouth", + "step", + "learn", + "three", + "floor", + "promise", + "breathe", + "darkness", + "push", + "earth", + "guess", + "save", + "song", + "above", + "along", + "both", + "color", + "house", + "almost", + "sorry", + "anymore", + "brother", + "okay", + "dear", + "game", + "fade", + "already", + "apart", + "warm", + "beauty", + "heard", + "notice", + "question", + "shine", + "began", + "piece", + "whole", + "shadow", + "secret", + "street", + "within", + "finger", + "point", + "morning", + "whisper", + "child", + "moon", + "green", + "story", + "glass", + "kid", + "silence", + "since", + "soft", + "yourself", + "empty", + "shall", + "angel", + "answer", + "baby", + "bright", + "dad", + "path", + "worry", + "hour", + "drop", + "follow", + "power", + "war", + "half", + "flow", + "heaven", + "act", + "chance", + "fact", + "least", + "tired", + "children", + "near", + "quite", + "afraid", + "rise", + "sea", + "taste", + "window", + "cover", + "nice", + "trust", + "lot", + "sad", + "cool", + "force", + "peace", + "return", + "blind", + "easy", + "ready", + "roll", + "rose", + "drive", + "held", + "music", + "beneath", + "hang", + "mom", + "paint", + "emotion", + "quiet", + "clear", + "cloud", + "few", + "pretty", + "bird", + "outside", + "paper", + "picture", + "front", + "rock", + "simple", + "anyone", + "meant", + "reality", + "road", + "sense", + "waste", + "bit", + "leaf", + "thank", + "happiness", + "meet", + "men", + "smoke", + "truly", + "decide", + "self", + "age", + "book", + "form", + "alive", + "carry", + "escape", + "damn", + "instead", + "able", + "ice", + "minute", + "throw", + "catch", + "leg", + "ring", + "course", + "goodbye", + "lead", + "poem", + "sick", + "corner", + "desire", + "known", + "problem", + "remind", + "shoulder", + "suppose", + "toward", + "wave", + "drink", + "jump", + "woman", + "pretend", + "sister", + "week", + "human", + "joy", + "crack", + "grey", + "pray", + "surprise", + "dry", + "knee", + "less", + "search", + "bleed", + "caught", + "clean", + "embrace", + "future", + "king", + "son", + "sorrow", + "chest", + "hug", + "remain", + "sat", + "worth", + "blow", + "daddy", + "final", + "parent", + "tight", + "also", + "create", + "lonely", + "safe", + "cross", + "dress", + "evil", + "silent", + "bone", + "fate", + "perhaps", + "anger", + "class", + "scar", + "snow", + "tiny", + "tonight", + "continue", + "control", + "dog", + "edge", + "mirror", + "month", + "suddenly", + "comfort", + "given", + "loud", + "quickly", + "gaze", + "plan", + "rush", + "stone", + "town", + "battle", + "ignore", + "spirit", + "stood", + "stupid", + "yours", + "brown", + "build", + "dust", + "hey", + "kept", + "pay", + "phone", + "twist", + "although", + "ball", + "beyond", + "hidden", + "nose", + "taken", + "fail", + "float", + "pure", + "somehow", + "wash", + "wrap", + "angry", + "cheek", + "creature", + "forgotten", + "heat", + "rip", + "single", + "space", + "special", + "weak", + "whatever", + "yell", + "anyway", + "blame", + "job", + "choose", + "country", + "curse", + "drift", + "echo", + "figure", + "grew", + "laughter", + "neck", + "suffer", + "worse", + "yeah", + "disappear", + "foot", + "forward", + "knife", + "mess", + "somewhere", + "stomach", + "storm", + "beg", + "idea", + "lift", + "offer", + "breeze", + "field", + "five", + "often", + "simply", + "stuck", + "win", + "allow", + "confuse", + "enjoy", + "except", + "flower", + "seek", + "strength", + "calm", + "grin", + "gun", + "heavy", + "hill", + "large", + "ocean", + "shoe", + "sigh", + "straight", + "summer", + "tongue", + "accept", + "crazy", + "everyday", + "exist", + "grass", + "mistake", + "sent", + "shut", + "surround", + "table", + "ache", + "brain", + "destroy", + "heal", + "nature", + "shout", + "sign", + "stain", + "choice", + "doubt", + "glance", + "glow", + "mountain", + "queen", + "stranger", + "throat", + "tomorrow", + "city", + "either", + "fish", + "flame", + "rather", + "shape", + "spin", + "spread", + "ash", + "distance", + "finish", + "image", + "imagine", + "important", + "nobody", + "shatter", + "warmth", + "became", + "feed", + "flesh", + "funny", + "lust", + "shirt", + "trouble", + "yellow", + "attention", + "bare", + "bite", + "money", + "protect", + "amaze", + "appear", + "born", + "choke", + "completely", + "daughter", + "fresh", + "friendship", + "gentle", + "probably", + "six", + "deserve", + "expect", + "grab", + "middle", + "nightmare", + "river", + "thousand", + "weight", + "worst", + "wound", + "barely", + "bottle", + "cream", + "regret", + "relationship", + "stick", + "test", + "crush", + "endless", + "fault", + "itself", + "rule", + "spill", + "art", + "circle", + "join", + "kick", + "mask", + "master", + "passion", + "quick", + "raise", + "smooth", + "unless", + "wander", + "actually", + "broke", + "chair", + "deal", + "favorite", + "gift", + "note", + "number", + "sweat", + "box", + "chill", + "clothes", + "lady", + "mark", + "park", + "poor", + "sadness", + "tie", + "animal", + "belong", + "brush", + "consume", + "dawn", + "forest", + "innocent", + "pen", + "pride", + "stream", + "thick", + "clay", + "complete", + "count", + "draw", + "faith", + "press", + "silver", + "struggle", + "surface", + "taught", + "teach", + "wet", + "bless", + "chase", + "climb", + "enter", + "letter", + "melt", + "metal", + "movie", + "stretch", + "swing", + "vision", + "wife", + "beside", + "crash", + "forgot", + "guide", + "haunt", + "joke", + "knock", + "plant", + "pour", + "prove", + "reveal", + "steal", + "stuff", + "trip", + "wood", + "wrist", + "bother", + "bottom", + "crawl", + "crowd", + "fix", + "forgive", + "frown", + "grace", + "loose", + "lucky", + "party", + "release", + "surely", + "survive", + "teacher", + "gently", + "grip", + "speed", + "suicide", + "travel", + "treat", + "vein", + "written", + "cage", + "chain", + "conversation", + "date", + "enemy", + "however", + "interest", + "million", + "page", + "pink", + "proud", + "sway", + "themselves", + "winter", + "church", + "cruel", + "cup", + "demon", + "experience", + "freedom", + "pair", + "pop", + "purpose", + "respect", + "shoot", + "softly", + "state", + "strange", + "bar", + "birth", + "curl", + "dirt", + "excuse", + "lord", + "lovely", + "monster", + "order", + "pack", + "pants", + "pool", + "scene", + "seven", + "shame", + "slide", + "ugly", + "among", + "blade", + "blonde", + "closet", + "creek", + "deny", + "drug", + "eternity", + "gain", + "grade", + "handle", + "key", + "linger", + "pale", + "prepare", + "swallow", + "swim", + "tremble", + "wheel", + "won", + "cast", + "cigarette", + "claim", + "college", + "direction", + "dirty", + "gather", + "ghost", + "hundred", + "loss", + "lung", + "orange", + "present", + "swear", + "swirl", + "twice", + "wild", + "bitter", + "blanket", + "doctor", + "everywhere", + "flash", + "grown", + "knowledge", + "numb", + "pressure", + "radio", + "repeat", + "ruin", + "spend", + "unknown", + "buy", + "clock", + "devil", + "early", + "false", + "fantasy", + "pound", + "precious", + "refuse", + "sheet", + "teeth", + "welcome", + "add", + "ahead", + "block", + "bury", + "caress", + "content", + "depth", + "despite", + "distant", + "marry", + "purple", + "threw", + "whenever", + "bomb", + "dull", + "easily", + "grasp", + "hospital", + "innocence", + "normal", + "receive", + "reply", + "rhyme", + "shade", + "someday", + "sword", + "toe", + "visit", + "asleep", + "bought", + "center", + "consider", + "flat", + "hero", + "history", + "ink", + "insane", + "muscle", + "mystery", + "pocket", + "reflection", + "shove", + "silently", + "smart", + "soldier", + "spot", + "stress", + "train", + "type", + "view", + "whether", + "bus", + "energy", + "explain", + "holy", + "hunger", + "inch", + "magic", + "mix", + "noise", + "nowhere", + "prayer", + "presence", + "shock", + "snap", + "spider", + "study", + "thunder", + "trail", + "admit", + "agree", + "bag", + "bang", + "bound", + "butterfly", + "cute", + "exactly", + "explode", + "familiar", + "fold", + "further", + "pierce", + "reflect", + "scent", + "selfish", + "sharp", + "sink", + "spring", + "stumble", + "universe", + "weep", + "women", + "wonderful", + "action", + "ancient", + "attempt", + "avoid", + "birthday", + "branch", + "chocolate", + "core", + "depress", + "drunk", + "especially", + "focus", + "fruit", + "honest", + "match", + "palm", + "perfectly", + "pillow", + "pity", + "poison", + "roar", + "shift", + "slightly", + "thump", + "truck", + "tune", + "twenty", + "unable", + "wipe", + "wrote", + "coat", + "constant", + "dinner", + "drove", + "egg", + "eternal", + "flight", + "flood", + "frame", + "freak", + "gasp", + "glad", + "hollow", + "motion", + "peer", + "plastic", + "root", + "screen", + "season", + "sting", + "strike", + "team", + "unlike", + "victim", + "volume", + "warn", + "weird", + "attack", + "await", + "awake", + "built", + "charm", + "crave", + "despair", + "fought", + "grant", + "grief", + "horse", + "limit", + "message", + "ripple", + "sanity", + "scatter", + "serve", + "split", + "string", + "trick", + "annoy", + "blur", + "boat", + "brave", + "clearly", + "cling", + "connect", + "fist", + "forth", + "imagination", + "iron", + "jock", + "judge", + "lesson", + "milk", + "misery", + "nail", + "naked", + "ourselves", + "poet", + "possible", + "princess", + "sail", + "size", + "snake", + "society", + "stroke", + "torture", + "toss", + "trace", + "wise", + "bloom", + "bullet", + "cell", + "check", + "cost", + "darling", + "during", + "footstep", + "fragile", + "hallway", + "hardly", + "horizon", + "invisible", + "journey", + "midnight", + "mud", + "nod", + "pause", + "relax", + "shiver", + "sudden", + "value", + "youth", + "abuse", + "admire", + "blink", + "breast", + "bruise", + "constantly", + "couple", + "creep", + "curve", + "difference", + "dumb", + "emptiness", + "gotta", + "honor", + "plain", + "planet", + "recall", + "rub", + "ship", + "slam", + "soar", + "somebody", + "tightly", + "weather", + "adore", + "approach", + "bond", + "bread", + "burst", + "candle", + "coffee", + "cousin", + "crime", + "desert", + "flutter", + "frozen", + "grand", + "heel", + "hello", + "language", + "level", + "movement", + "pleasure", + "powerful", + "random", + "rhythm", + "settle", + "silly", + "slap", + "sort", + "spoken", + "steel", + "threaten", + "tumble", + "upset", + "aside", + "awkward", + "bee", + "blank", + "board", + "button", + "card", + "carefully", + "complain", + "crap", + "deeply", + "discover", + "drag", + "dread", + "effort", + "entire", + "fairy", + "giant", + "gotten", + "greet", + "illusion", + "jeans", + "leap", + "liquid", + "march", + "mend", + "nervous", + "nine", + "replace", + "rope", + "spine", + "stole", + "terror", + "accident", + "apple", + "balance", + "boom", + "childhood", + "collect", + "demand", + "depression", + "eventually", + "faint", + "glare", + "goal", + "group", + "honey", + "kitchen", + "laid", + "limb", + "machine", + "mere", + "mold", + "murder", + "nerve", + "painful", + "poetry", + "prince", + "rabbit", + "shelter", + "shore", + "shower", + "soothe", + "stair", + "steady", + "sunlight", + "tangle", + "tease", + "treasure", + "uncle", + "begun", + "bliss", + "canvas", + "cheer", + "claw", + "clutch", + "commit", + "crimson", + "crystal", + "delight", + "doll", + "existence", + "express", + "fog", + "football", + "gay", + "goose", + "guard", + "hatred", + "illuminate", + "mass", + "math", + "mourn", + "rich", + "rough", + "skip", + "stir", + "student", + "style", + "support", + "thorn", + "tough", + "yard", + "yearn", + "yesterday", + "advice", + "appreciate", + "autumn", + "bank", + "beam", + "bowl", + "capture", + "carve", + "collapse", + "confusion", + "creation", + "dove", + "feather", + "girlfriend", + "glory", + "government", + "harsh", + "hop", + "inner", + "loser", + "moonlight", + "neighbor", + "neither", + "peach", + "pig", + "praise", + "screw", + "shield", + "shimmer", + "sneak", + "stab", + "subject", + "throughout", + "thrown", + "tower", + "twirl", + "wow", + "army", + "arrive", + "bathroom", + "bump", + "cease", + "cookie", + "couch", + "courage", + "dim", + "guilt", + "howl", + "hum", + "husband", + "insult", + "led", + "lunch", + "mock", + "mostly", + "natural", + "nearly", + "needle", + "nerd", + "peaceful", + "perfection", + "pile", + "price", + "remove", + "roam", + "sanctuary", + "serious", + "shiny", + "shook", + "sob", + "stolen", + "tap", + "vain", + "void", + "warrior", + "wrinkle", + "affection", + "apologize", + "blossom", + "bounce", + "bridge", + "cheap", + "crumble", + "decision", + "descend", + "desperately", + "dig", + "dot", + "flip", + "frighten", + "heartbeat", + "huge", + "lazy", + "lick", + "odd", + "opinion", + "process", + "puzzle", + "quietly", + "retreat", + "score", + "sentence", + "separate", + "situation", + "skill", + "soak", + "square", + "stray", + "taint", + "task", + "tide", + "underneath", + "veil", + "whistle", + "anywhere", + "bedroom", + "bid", + "bloody", + "burden", + "careful", + "compare", + "concern", + "curtain", + "decay", + "defeat", + "describe", + "double", + "dreamer", + "driver", + "dwell", + "evening", + "flare", + "flicker", + "grandma", + "guitar", + "harm", + "horrible", + "hungry", + "indeed", + "lace", + "melody", + "monkey", + "nation", + "object", + "obviously", + "rainbow", + "salt", + "scratch", + "shown", + "shy", + "stage", + "stun", + "third", + "tickle", + "useless", + "weakness", + "worship", + "worthless", + "afternoon", + "beard", + "boyfriend", + "bubble", + "busy", + "certain", + "chin", + "concrete", + "desk", + "diamond", + "doom", + "drawn", + "due", + "felicity", + "freeze", + "frost", + "garden", + "glide", + "harmony", + "hopefully", + "hunt", + "jealous", + "lightning", + "mama", + "mercy", + "peel", + "physical", + "position", + "pulse", + "punch", + "quit", + "rant", + "respond", + "salty", + "sane", + "satisfy", + "savior", + "sheep", + "slept", + "social", + "sport", + "tuck", + "utter", + "valley", + "wolf", + "aim", + "alas", + "alter", + "arrow", + "awaken", + "beaten", + "belief", + "brand", + "ceiling", + "cheese", + "clue", + "confidence", + "connection", + "daily", + "disguise", + "eager", + "erase", + "essence", + "everytime", + "expression", + "fan", + "flag", + "flirt", + "foul", + "fur", + "giggle", + "glorious", + "ignorance", + "law", + "lifeless", + "measure", + "mighty", + "muse", + "north", + "opposite", + "paradise", + "patience", + "patient", + "pencil", + "petal", + "plate", + "ponder", + "possibly", + "practice", + "slice", + "spell", + "stock", + "strife", + "strip", + "suffocate", + "suit", + "tender", + "tool", + "trade", + "velvet", + "verse", + "waist", + "witch", + "aunt", + "bench", + "bold", + "cap", + "certainly", + "click", + "companion", + "creator", + "dart", + "delicate", + "determine", + "dish", + "dragon", + "drama", + "drum", + "dude", + "everybody", + "feast", + "forehead", + "former", + "fright", + "fully", + "gas", + "hook", + "hurl", + "invite", + "juice", + "manage", + "moral", + "possess", + "raw", + "rebel", + "royal", + "scale", + "scary", + "several", + "slight", + "stubborn", + "swell", + "talent", + "tea", + "terrible", + "thread", + "torment", + "trickle", + "usually", + "vast", + "violence", + "weave", + "acid", + "agony", + "ashamed", + "awe", + "belly", + "blend", + "blush", + "character", + "cheat", + "common", + "company", + "coward", + "creak", + "danger", + "deadly", + "defense", + "define", + "depend", + "desperate", + "destination", + "dew", + "duck", + "dusty", + "embarrass", + "engine", + "example", + "explore", + "foe", + "freely", + "frustrate", + "generation", + "glove", + "guilty", + "health", + "hurry", + "idiot", + "impossible", + "inhale", + "jaw", + "kingdom", + "mention", + "mist", + "moan", + "mumble", + "mutter", + "observe", + "ode", + "pathetic", + "pattern", + "pie", + "prefer", + "puff", + "rape", + "rare", + "revenge", + "rude", + "scrape", + "spiral", + "squeeze", + "strain", + "sunset", + "suspend", + "sympathy", + "thigh", + "throne", + "total", + "unseen", + "weapon", + "weary" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/de.json b/coins/monero/src/wallet/seed/classic/de.json new file mode 100644 index 00000000..caaf9c67 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/de.json @@ -0,0 +1,1628 @@ +[ + "Abakus", + "Abart", + "abbilden", + "Abbruch", + "Abdrift", + "Abendrot", + "Abfahrt", + "abfeuern", + "Abflug", + "abfragen", + "Abglanz", + "abhärten", + "abheben", + "Abhilfe", + "Abitur", + "Abkehr", + "Ablauf", + "ablecken", + "Ablösung", + "Abnehmer", + "abnutzen", + "Abonnent", + "Abrasion", + "Abrede", + "abrüsten", + "Absicht", + "Absprung", + "Abstand", + "absuchen", + "Abteil", + "Abundanz", + "abwarten", + "Abwurf", + "Abzug", + "Achse", + "Achtung", + "Acker", + "Aderlass", + "Adler", + "Admiral", + "Adresse", + "Affe", + "Affront", + "Afrika", + "Aggregat", + "Agilität", + "ähneln", + "Ahnung", + "Ahorn", + "Akazie", + "Akkord", + "Akrobat", + "Aktfoto", + "Aktivist", + "Albatros", + "Alchimie", + "Alemanne", + "Alibi", + "Alkohol", + "Allee", + "Allüre", + "Almosen", + "Almweide", + "Aloe", + "Alpaka", + "Alpental", + "Alphabet", + "Alpinist", + "Alraune", + "Altbier", + "Alter", + "Altflöte", + "Altruist", + "Alublech", + "Aludose", + "Amateur", + "Amazonas", + "Ameise", + "Amnesie", + "Amok", + "Ampel", + "Amphibie", + "Ampulle", + "Amsel", + "Amulett", + "Anakonda", + "Analogie", + "Ananas", + "Anarchie", + "Anatomie", + "Anbau", + "Anbeginn", + "anbieten", + "Anblick", + "ändern", + "andocken", + "Andrang", + "anecken", + "Anflug", + "Anfrage", + "Anführer", + "Angebot", + "Angler", + "Anhalter", + "Anhöhe", + "Animator", + "Anis", + "Anker", + "ankleben", + "Ankunft", + "Anlage", + "anlocken", + "Anmut", + "Annahme", + "Anomalie", + "Anonymus", + "Anorak", + "anpeilen", + "Anrecht", + "Anruf", + "Ansage", + "Anschein", + "Ansicht", + "Ansporn", + "Anteil", + "Antlitz", + "Antrag", + "Antwort", + "Anwohner", + "Aorta", + "Apfel", + "Appetit", + "Applaus", + "Aquarium", + "Arbeit", + "Arche", + "Argument", + "Arktis", + "Armband", + "Aroma", + "Asche", + "Askese", + "Asphalt", + "Asteroid", + "Ästhetik", + "Astronom", + "Atelier", + "Athlet", + "Atlantik", + "Atmung", + "Audienz", + "aufatmen", + "Auffahrt", + "aufholen", + "aufregen", + "Aufsatz", + "Auftritt", + "Aufwand", + "Augapfel", + "Auktion", + "Ausbruch", + "Ausflug", + "Ausgabe", + "Aushilfe", + "Ausland", + "Ausnahme", + "Aussage", + "Autobahn", + "Avocado", + "Axthieb", + "Bach", + "backen", + "Badesee", + "Bahnhof", + "Balance", + "Balkon", + "Ballett", + "Balsam", + "Banane", + "Bandage", + "Bankett", + "Barbar", + "Barde", + "Barett", + "Bargeld", + "Barkasse", + "Barriere", + "Bart", + "Bass", + "Bastler", + "Batterie", + "Bauch", + "Bauer", + "Bauholz", + "Baujahr", + "Baum", + "Baustahl", + "Bauteil", + "Bauweise", + "Bazar", + "beachten", + "Beatmung", + "beben", + "Becher", + "Becken", + "bedanken", + "beeilen", + "beenden", + "Beere", + "befinden", + "Befreier", + "Begabung", + "Begierde", + "begrüßen", + "Beiboot", + "Beichte", + "Beifall", + "Beigabe", + "Beil", + "Beispiel", + "Beitrag", + "beizen", + "bekommen", + "beladen", + "Beleg", + "bellen", + "belohnen", + "Bemalung", + "Bengel", + "Benutzer", + "Benzin", + "beraten", + "Bereich", + "Bergluft", + "Bericht", + "Bescheid", + "Besitz", + "besorgen", + "Bestand", + "Besuch", + "betanken", + "beten", + "betören", + "Bett", + "Beule", + "Beute", + "Bewegung", + "bewirken", + "Bewohner", + "bezahlen", + "Bezug", + "biegen", + "Biene", + "Bierzelt", + "bieten", + "Bikini", + "Bildung", + "Billard", + "binden", + "Biobauer", + "Biologe", + "Bionik", + "Biotop", + "Birke", + "Bison", + "Bitte", + "Biwak", + "Bizeps", + "blasen", + "Blatt", + "Blauwal", + "Blende", + "Blick", + "Blitz", + "Blockade", + "Blödelei", + "Blondine", + "Blues", + "Blume", + "Blut", + "Bodensee", + "Bogen", + "Boje", + "Bollwerk", + "Bonbon", + "Bonus", + "Boot", + "Bordarzt", + "Börse", + "Böschung", + "Boudoir", + "Boxkampf", + "Boykott", + "Brahms", + "Brandung", + "Brauerei", + "Brecher", + "Breitaxt", + "Bremse", + "brennen", + "Brett", + "Brief", + "Brigade", + "Brillanz", + "bringen", + "brodeln", + "Brosche", + "Brötchen", + "Brücke", + "Brunnen", + "Brüste", + "Brutofen", + "Buch", + "Büffel", + "Bugwelle", + "Bühne", + "Buletten", + "Bullauge", + "Bumerang", + "bummeln", + "Buntglas", + "Bürde", + "Burgherr", + "Bursche", + "Busen", + "Buslinie", + "Bussard", + "Butangas", + "Butter", + "Cabrio", + "campen", + "Captain", + "Cartoon", + "Cello", + "Chalet", + "Charisma", + "Chefarzt", + "Chiffon", + "Chipsatz", + "Chirurg", + "Chor", + "Chronik", + "Chuzpe", + "Clubhaus", + "Cockpit", + "Codewort", + "Cognac", + "Coladose", + "Computer", + "Coupon", + "Cousin", + "Cracking", + "Crash", + "Curry", + "Dach", + "Dackel", + "daddeln", + "daliegen", + "Dame", + "Dammbau", + "Dämon", + "Dampflok", + "Dank", + "Darm", + "Datei", + "Datsche", + "Datteln", + "Datum", + "Dauer", + "Daunen", + "Deckel", + "Decoder", + "Defekt", + "Degen", + "Dehnung", + "Deiche", + "Dekade", + "Dekor", + "Delfin", + "Demut", + "denken", + "Deponie", + "Design", + "Desktop", + "Dessert", + "Detail", + "Detektiv", + "Dezibel", + "Diadem", + "Diagnose", + "Dialekt", + "Diamant", + "Dichter", + "Dickicht", + "Diesel", + "Diktat", + "Diplom", + "Direktor", + "Dirne", + "Diskurs", + "Distanz", + "Docht", + "Dohle", + "Dolch", + "Domäne", + "Donner", + "Dorade", + "Dorf", + "Dörrobst", + "Dorsch", + "Dossier", + "Dozent", + "Drachen", + "Draht", + "Drama", + "Drang", + "Drehbuch", + "Dreieck", + "Dressur", + "Drittel", + "Drossel", + "Druck", + "Duell", + "Duft", + "Düne", + "Dünung", + "dürfen", + "Duschbad", + "Düsenjet", + "Dynamik", + "Ebbe", + "Echolot", + "Echse", + "Eckball", + "Edding", + "Edelweiß", + "Eden", + "Edition", + "Efeu", + "Effekte", + "Egoismus", + "Ehre", + "Eiablage", + "Eiche", + "Eidechse", + "Eidotter", + "Eierkopf", + "Eigelb", + "Eiland", + "Eilbote", + "Eimer", + "einatmen", + "Einband", + "Eindruck", + "Einfall", + "Eingang", + "Einkauf", + "einladen", + "Einöde", + "Einrad", + "Eintopf", + "Einwurf", + "Einzug", + "Eisbär", + "Eisen", + "Eishöhle", + "Eismeer", + "Eiweiß", + "Ekstase", + "Elan", + "Elch", + "Elefant", + "Eleganz", + "Element", + "Elfe", + "Elite", + "Elixier", + "Ellbogen", + "Eloquenz", + "Emigrant", + "Emission", + "Emotion", + "Empathie", + "Empfang", + "Endzeit", + "Energie", + "Engpass", + "Enkel", + "Enklave", + "Ente", + "entheben", + "Entität", + "entladen", + "Entwurf", + "Episode", + "Epoche", + "erachten", + "Erbauer", + "erblühen", + "Erdbeere", + "Erde", + "Erdgas", + "Erdkunde", + "Erdnuss", + "Erdöl", + "Erdteil", + "Ereignis", + "Eremit", + "erfahren", + "Erfolg", + "erfreuen", + "erfüllen", + "Ergebnis", + "erhitzen", + "erkalten", + "erkennen", + "erleben", + "Erlösung", + "ernähren", + "erneuern", + "Ernte", + "Eroberer", + "eröffnen", + "Erosion", + "Erotik", + "Erpel", + "erraten", + "Erreger", + "erröten", + "Ersatz", + "Erstflug", + "Ertrag", + "Eruption", + "erwarten", + "erwidern", + "Erzbau", + "Erzeuger", + "erziehen", + "Esel", + "Eskimo", + "Eskorte", + "Espe", + "Espresso", + "essen", + "Etage", + "Etappe", + "Etat", + "Ethik", + "Etikett", + "Etüde", + "Eule", + "Euphorie", + "Europa", + "Everest", + "Examen", + "Exil", + "Exodus", + "Extrakt", + "Fabel", + "Fabrik", + "Fachmann", + "Fackel", + "Faden", + "Fagott", + "Fahne", + "Faible", + "Fairness", + "Fakt", + "Fakultät", + "Falke", + "Fallobst", + "Fälscher", + "Faltboot", + "Familie", + "Fanclub", + "Fanfare", + "Fangarm", + "Fantasie", + "Farbe", + "Farmhaus", + "Farn", + "Fasan", + "Faser", + "Fassung", + "fasten", + "Faulheit", + "Fauna", + "Faust", + "Favorit", + "Faxgerät", + "Fazit", + "fechten", + "Federboa", + "Fehler", + "Feier", + "Feige", + "feilen", + "Feinripp", + "Feldbett", + "Felge", + "Fellpony", + "Felswand", + "Ferien", + "Ferkel", + "Fernweh", + "Ferse", + "Fest", + "Fettnapf", + "Feuer", + "Fiasko", + "Fichte", + "Fiktion", + "Film", + "Filter", + "Filz", + "Finanzen", + "Findling", + "Finger", + "Fink", + "Finnwal", + "Fisch", + "Fitness", + "Fixpunkt", + "Fixstern", + "Fjord", + "Flachbau", + "Flagge", + "Flamenco", + "Flanke", + "Flasche", + "Flaute", + "Fleck", + "Flegel", + "flehen", + "Fleisch", + "fliegen", + "Flinte", + "Flirt", + "Flocke", + "Floh", + "Floskel", + "Floß", + "Flöte", + "Flugzeug", + "Flunder", + "Flusstal", + "Flutung", + "Fockmast", + "Fohlen", + "Föhnlage", + "Fokus", + "folgen", + "Foliant", + "Folklore", + "Fontäne", + "Förde", + "Forelle", + "Format", + "Forscher", + "Fortgang", + "Forum", + "Fotograf", + "Frachter", + "Fragment", + "Fraktion", + "fräsen", + "Frauenpo", + "Freak", + "Fregatte", + "Freiheit", + "Freude", + "Frieden", + "Frohsinn", + "Frosch", + "Frucht", + "Frühjahr", + "Fuchs", + "Fügung", + "fühlen", + "Füller", + "Fundbüro", + "Funkboje", + "Funzel", + "Furnier", + "Fürsorge", + "Fusel", + "Fußbad", + "Futteral", + "Gabelung", + "gackern", + "Gage", + "gähnen", + "Galaxie", + "Galeere", + "Galopp", + "Gameboy", + "Gamsbart", + "Gandhi", + "Gang", + "Garage", + "Gardine", + "Garküche", + "Garten", + "Gasthaus", + "Gattung", + "gaukeln", + "Gazelle", + "Gebäck", + "Gebirge", + "Gebräu", + "Geburt", + "Gedanke", + "Gedeck", + "Gedicht", + "Gefahr", + "Gefieder", + "Geflügel", + "Gefühl", + "Gegend", + "Gehirn", + "Gehöft", + "Gehweg", + "Geige", + "Geist", + "Gelage", + "Geld", + "Gelenk", + "Gelübde", + "Gemälde", + "Gemeinde", + "Gemüse", + "genesen", + "Genuss", + "Gepäck", + "Geranie", + "Gericht", + "Germane", + "Geruch", + "Gesang", + "Geschenk", + "Gesetz", + "Gesindel", + "Gesöff", + "Gespan", + "Gestade", + "Gesuch", + "Getier", + "Getränk", + "Getümmel", + "Gewand", + "Geweih", + "Gewitter", + "Gewölbe", + "Geysir", + "Giftzahn", + "Gipfel", + "Giraffe", + "Gitarre", + "glänzen", + "Glasauge", + "Glatze", + "Gleis", + "Globus", + "Glück", + "glühen", + "Glutofen", + "Goldzahn", + "Gondel", + "gönnen", + "Gottheit", + "graben", + "Grafik", + "Grashalm", + "Graugans", + "greifen", + "Grenze", + "grillen", + "Groschen", + "Grotte", + "Grube", + "Grünalge", + "Gruppe", + "gruseln", + "Gulasch", + "Gummibär", + "Gurgel", + "Gürtel", + "Güterzug", + "Haarband", + "Habicht", + "hacken", + "hadern", + "Hafen", + "Hagel", + "Hähnchen", + "Haifisch", + "Haken", + "Halbaffe", + "Halsader", + "halten", + "Halunke", + "Handbuch", + "Hanf", + "Harfe", + "Harnisch", + "härten", + "Harz", + "Hasenohr", + "Haube", + "hauchen", + "Haupt", + "Haut", + "Havarie", + "Hebamme", + "hecheln", + "Heck", + "Hedonist", + "Heiler", + "Heimat", + "Heizung", + "Hektik", + "Held", + "helfen", + "Helium", + "Hemd", + "hemmen", + "Hengst", + "Herd", + "Hering", + "Herkunft", + "Hermelin", + "Herrchen", + "Herzdame", + "Heulboje", + "Hexe", + "Hilfe", + "Himbeere", + "Himmel", + "Hingabe", + "hinhören", + "Hinweis", + "Hirsch", + "Hirte", + "Hitzkopf", + "Hobel", + "Hochform", + "Hocker", + "hoffen", + "Hofhund", + "Hofnarr", + "Höhenzug", + "Hohlraum", + "Hölle", + "Holzboot", + "Honig", + "Honorar", + "horchen", + "Hörprobe", + "Höschen", + "Hotel", + "Hubraum", + "Hufeisen", + "Hügel", + "huldigen", + "Hülle", + "Humbug", + "Hummer", + "Humor", + "Hund", + "Hunger", + "Hupe", + "Hürde", + "Hurrikan", + "Hydrant", + "Hypnose", + "Ibis", + "Idee", + "Idiot", + "Igel", + "Illusion", + "Imitat", + "impfen", + "Import", + "Inferno", + "Ingwer", + "Inhalte", + "Inland", + "Insekt", + "Ironie", + "Irrfahrt", + "Irrtum", + "Isolator", + "Istwert", + "Jacke", + "Jade", + "Jagdhund", + "Jäger", + "Jaguar", + "Jahr", + "Jähzorn", + "Jazzfest", + "Jetpilot", + "jobben", + "Jochbein", + "jodeln", + "Jodsalz", + "Jolle", + "Journal", + "Jubel", + "Junge", + "Junimond", + "Jupiter", + "Jutesack", + "Juwel", + "Kabarett", + "Kabine", + "Kabuff", + "Käfer", + "Kaffee", + "Kahlkopf", + "Kaimauer", + "Kajüte", + "Kaktus", + "Kaliber", + "Kaltluft", + "Kamel", + "kämmen", + "Kampagne", + "Kanal", + "Känguru", + "Kanister", + "Kanone", + "Kante", + "Kanu", + "kapern", + "Kapitän", + "Kapuze", + "Karneval", + "Karotte", + "Käsebrot", + "Kasper", + "Kastanie", + "Katalog", + "Kathode", + "Katze", + "kaufen", + "Kaugummi", + "Kauz", + "Kehle", + "Keilerei", + "Keksdose", + "Kellner", + "Keramik", + "Kerze", + "Kessel", + "Kette", + "keuchen", + "kichern", + "Kielboot", + "Kindheit", + "Kinnbart", + "Kinosaal", + "Kiosk", + "Kissen", + "Klammer", + "Klang", + "Klapprad", + "Klartext", + "kleben", + "Klee", + "Kleinod", + "Klima", + "Klingel", + "Klippe", + "Klischee", + "Kloster", + "Klugheit", + "Klüngel", + "kneten", + "Knie", + "Knöchel", + "knüpfen", + "Kobold", + "Kochbuch", + "Kohlrabi", + "Koje", + "Kokosöl", + "Kolibri", + "Kolumne", + "Kombüse", + "Komiker", + "kommen", + "Konto", + "Konzept", + "Kopfkino", + "Kordhose", + "Korken", + "Korsett", + "Kosename", + "Krabbe", + "Krach", + "Kraft", + "Krähe", + "Kralle", + "Krapfen", + "Krater", + "kraulen", + "Kreuz", + "Krokodil", + "Kröte", + "Kugel", + "Kuhhirt", + "Kühnheit", + "Künstler", + "Kurort", + "Kurve", + "Kurzfilm", + "kuscheln", + "küssen", + "Kutter", + "Labor", + "lachen", + "Lackaffe", + "Ladeluke", + "Lagune", + "Laib", + "Lakritze", + "Lammfell", + "Land", + "Langmut", + "Lappalie", + "Last", + "Laterne", + "Latzhose", + "Laubsäge", + "laufen", + "Laune", + "Lausbub", + "Lavasee", + "Leben", + "Leder", + "Leerlauf", + "Lehm", + "Lehrer", + "leihen", + "Lektüre", + "Lenker", + "Lerche", + "Leseecke", + "Leuchter", + "Lexikon", + "Libelle", + "Libido", + "Licht", + "Liebe", + "liefern", + "Liftboy", + "Limonade", + "Lineal", + "Linoleum", + "List", + "Liveband", + "Lobrede", + "locken", + "Löffel", + "Logbuch", + "Logik", + "Lohn", + "Loipe", + "Lokal", + "Lorbeer", + "Lösung", + "löten", + "Lottofee", + "Löwe", + "Luchs", + "Luder", + "Luftpost", + "Luke", + "Lümmel", + "Lunge", + "lutschen", + "Luxus", + "Macht", + "Magazin", + "Magier", + "Magnet", + "mähen", + "Mahlzeit", + "Mahnmal", + "Maibaum", + "Maisbrei", + "Makel", + "malen", + "Mammut", + "Maniküre", + "Mantel", + "Marathon", + "Marder", + "Marine", + "Marke", + "Marmor", + "Märzluft", + "Maske", + "Maßanzug", + "Maßkrug", + "Mastkorb", + "Material", + "Matratze", + "Mauerbau", + "Maulkorb", + "Mäuschen", + "Mäzen", + "Medium", + "Meinung", + "melden", + "Melodie", + "Mensch", + "Merkmal", + "Messe", + "Metall", + "Meteor", + "Methode", + "Metzger", + "Mieze", + "Milchkuh", + "Mimose", + "Minirock", + "Minute", + "mischen", + "Missetat", + "mitgehen", + "Mittag", + "Mixtape", + "Möbel", + "Modul", + "mögen", + "Möhre", + "Molch", + "Moment", + "Monat", + "Mondflug", + "Monitor", + "Monokini", + "Monster", + "Monument", + "Moorhuhn", + "Moos", + "Möpse", + "Moral", + "Mörtel", + "Motiv", + "Motorrad", + "Möwe", + "Mühe", + "Mulatte", + "Müller", + "Mumie", + "Mund", + "Münze", + "Muschel", + "Muster", + "Mythos", + "Nabel", + "Nachtzug", + "Nackedei", + "Nagel", + "Nähe", + "Nähnadel", + "Namen", + "Narbe", + "Narwal", + "Nasenbär", + "Natur", + "Nebel", + "necken", + "Neffe", + "Neigung", + "Nektar", + "Nenner", + "Neptun", + "Nerz", + "Nessel", + "Nestbau", + "Netz", + "Neubau", + "Neuerung", + "Neugier", + "nicken", + "Niere", + "Nilpferd", + "nisten", + "Nocke", + "Nomade", + "Nordmeer", + "Notdurft", + "Notstand", + "Notwehr", + "Nudismus", + "Nuss", + "Nutzhanf", + "Oase", + "Obdach", + "Oberarzt", + "Objekt", + "Oboe", + "Obsthain", + "Ochse", + "Odyssee", + "Ofenholz", + "öffnen", + "Ohnmacht", + "Ohrfeige", + "Ohrwurm", + "Ökologie", + "Oktave", + "Ölberg", + "Olive", + "Ölkrise", + "Omelett", + "Onkel", + "Oper", + "Optiker", + "Orange", + "Orchidee", + "ordnen", + "Orgasmus", + "Orkan", + "Ortskern", + "Ortung", + "Ostasien", + "Ozean", + "Paarlauf", + "Packeis", + "paddeln", + "Paket", + "Palast", + "Pandabär", + "Panik", + "Panorama", + "Panther", + "Papagei", + "Papier", + "Paprika", + "Paradies", + "Parka", + "Parodie", + "Partner", + "Passant", + "Patent", + "Patzer", + "Pause", + "Pavian", + "Pedal", + "Pegel", + "peilen", + "Perle", + "Person", + "Pfad", + "Pfau", + "Pferd", + "Pfleger", + "Physik", + "Pier", + "Pilotwal", + "Pinzette", + "Piste", + "Plakat", + "Plankton", + "Platin", + "Plombe", + "plündern", + "Pobacke", + "Pokal", + "polieren", + "Popmusik", + "Porträt", + "Posaune", + "Postamt", + "Pottwal", + "Pracht", + "Pranke", + "Preis", + "Primat", + "Prinzip", + "Protest", + "Proviant", + "Prüfung", + "Pubertät", + "Pudding", + "Pullover", + "Pulsader", + "Punkt", + "Pute", + "Putsch", + "Puzzle", + "Python", + "quaken", + "Qualle", + "Quark", + "Quellsee", + "Querkopf", + "Quitte", + "Quote", + "Rabauke", + "Rache", + "Radclub", + "Radhose", + "Radio", + "Radtour", + "Rahmen", + "Rampe", + "Randlage", + "Ranzen", + "Rapsöl", + "Raserei", + "rasten", + "Rasur", + "Rätsel", + "Raubtier", + "Raumzeit", + "Rausch", + "Reaktor", + "Realität", + "Rebell", + "Rede", + "Reetdach", + "Regatta", + "Regen", + "Rehkitz", + "Reifen", + "Reim", + "Reise", + "Reizung", + "Rekord", + "Relevanz", + "Rennboot", + "Respekt", + "Restmüll", + "retten", + "Reue", + "Revolte", + "Rhetorik", + "Rhythmus", + "Richtung", + "Riegel", + "Rindvieh", + "Rippchen", + "Ritter", + "Robbe", + "Roboter", + "Rockband", + "Rohdaten", + "Roller", + "Roman", + "röntgen", + "Rose", + "Rosskur", + "Rost", + "Rotahorn", + "Rotglut", + "Rotznase", + "Rubrik", + "Rückweg", + "Rufmord", + "Ruhe", + "Ruine", + "Rumpf", + "Runde", + "Rüstung", + "rütteln", + "Saaltür", + "Saatguts", + "Säbel", + "Sachbuch", + "Sack", + "Saft", + "sagen", + "Sahneeis", + "Salat", + "Salbe", + "Salz", + "Sammlung", + "Samt", + "Sandbank", + "Sanftmut", + "Sardine", + "Satire", + "Sattel", + "Satzbau", + "Sauerei", + "Saum", + "Säure", + "Schall", + "Scheitel", + "Schiff", + "Schlager", + "Schmied", + "Schnee", + "Scholle", + "Schrank", + "Schulbus", + "Schwan", + "Seeadler", + "Seefahrt", + "Seehund", + "Seeufer", + "segeln", + "Sehnerv", + "Seide", + "Seilzug", + "Senf", + "Sessel", + "Seufzer", + "Sexgott", + "Sichtung", + "Signal", + "Silber", + "singen", + "Sinn", + "Sirup", + "Sitzbank", + "Skandal", + "Skikurs", + "Skipper", + "Skizze", + "Smaragd", + "Socke", + "Sohn", + "Sommer", + "Songtext", + "Sorte", + "Spagat", + "Spannung", + "Spargel", + "Specht", + "Speiseöl", + "Spiegel", + "Sport", + "spülen", + "Stadtbus", + "Stall", + "Stärke", + "Stativ", + "staunen", + "Stern", + "Stiftung", + "Stollen", + "Strömung", + "Sturm", + "Substanz", + "Südalpen", + "Sumpf", + "surfen", + "Tabak", + "Tafel", + "Tagebau", + "takeln", + "Taktung", + "Talsohle", + "Tand", + "Tanzbär", + "Tapir", + "Tarantel", + "Tarnname", + "Tasse", + "Tatnacht", + "Tatsache", + "Tatze", + "Taube", + "tauchen", + "Taufpate", + "Taumel", + "Teelicht", + "Teich", + "teilen", + "Tempo", + "Tenor", + "Terrasse", + "Testflug", + "Theater", + "Thermik", + "ticken", + "Tiefflug", + "Tierart", + "Tigerhai", + "Tinte", + "Tischler", + "toben", + "Toleranz", + "Tölpel", + "Tonband", + "Topf", + "Topmodel", + "Torbogen", + "Torlinie", + "Torte", + "Tourist", + "Tragesel", + "trampeln", + "Trapez", + "Traum", + "treffen", + "Trennung", + "Treue", + "Trick", + "trimmen", + "Trödel", + "Trost", + "Trumpf", + "tüfteln", + "Turban", + "Turm", + "Übermut", + "Ufer", + "Uhrwerk", + "umarmen", + "Umbau", + "Umfeld", + "Umgang", + "Umsturz", + "Unart", + "Unfug", + "Unimog", + "Unruhe", + "Unwucht", + "Uranerz", + "Urlaub", + "Urmensch", + "Utopie", + "Vakuum", + "Valuta", + "Vandale", + "Vase", + "Vektor", + "Ventil", + "Verb", + "Verdeck", + "Verfall", + "Vergaser", + "verhexen", + "Verlag", + "Vers", + "Vesper", + "Vieh", + "Viereck", + "Vinyl", + "Virus", + "Vitrine", + "Vollblut", + "Vorbote", + "Vorrat", + "Vorsicht", + "Vulkan", + "Wachstum", + "Wade", + "Wagemut", + "Wahlen", + "Wahrheit", + "Wald", + "Walhai", + "Wallach", + "Walnuss", + "Walzer", + "wandeln", + "Wanze", + "wärmen", + "Warnruf", + "Wäsche", + "Wasser", + "Weberei", + "wechseln", + "Wegegeld", + "wehren", + "Weiher", + "Weinglas", + "Weißbier", + "Weitwurf", + "Welle", + "Weltall", + "Werkbank", + "Werwolf", + "Wetter", + "wiehern", + "Wildgans", + "Wind", + "Wohl", + "Wohnort", + "Wolf", + "Wollust", + "Wortlaut", + "Wrack", + "Wunder", + "Wurfaxt", + "Wurst", + "Yacht", + "Yeti", + "Zacke", + "Zahl", + "zähmen", + "Zahnfee", + "Zäpfchen", + "Zaster", + "Zaumzeug", + "Zebra", + "zeigen", + "Zeitlupe", + "Zellkern", + "Zeltdach", + "Zensor", + "Zerfall", + "Zeug", + "Ziege", + "Zielfoto", + "Zimteis", + "Zobel", + "Zollhund", + "Zombie", + "Zöpfe", + "Zucht", + "Zufahrt", + "Zugfahrt", + "Zugvogel", + "Zündung", + "Zweck", + "Zyklop" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/en.json b/coins/monero/src/wallet/seed/classic/en.json new file mode 100644 index 00000000..5cb21268 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/en.json @@ -0,0 +1,1628 @@ +[ + "abbey", + "abducts", + "ability", + "ablaze", + "abnormal", + "abort", + "abrasive", + "absorb", + "abyss", + "academy", + "aces", + "aching", + "acidic", + "acoustic", + "acquire", + "across", + "actress", + "acumen", + "adapt", + "addicted", + "adept", + "adhesive", + "adjust", + "adopt", + "adrenalin", + "adult", + "adventure", + "aerial", + "afar", + "affair", + "afield", + "afloat", + "afoot", + "afraid", + "after", + "against", + "agenda", + "aggravate", + "agile", + "aglow", + "agnostic", + "agony", + "agreed", + "ahead", + "aided", + "ailments", + "aimless", + "airport", + "aisle", + "ajar", + "akin", + "alarms", + "album", + "alchemy", + "alerts", + "algebra", + "alkaline", + "alley", + "almost", + "aloof", + "alpine", + "already", + "also", + "altitude", + "alumni", + "always", + "amaze", + "ambush", + "amended", + "amidst", + "ammo", + "amnesty", + "among", + "amply", + "amused", + "anchor", + "android", + "anecdote", + "angled", + "ankle", + "annoyed", + "answers", + "antics", + "anvil", + "anxiety", + "anybody", + "apart", + "apex", + "aphid", + "aplomb", + "apology", + "apply", + "apricot", + "aptitude", + "aquarium", + "arbitrary", + "archer", + "ardent", + "arena", + "argue", + "arises", + "army", + "around", + "arrow", + "arsenic", + "artistic", + "ascend", + "ashtray", + "aside", + "asked", + "asleep", + "aspire", + "assorted", + "asylum", + "athlete", + "atlas", + "atom", + "atrium", + "attire", + "auburn", + "auctions", + "audio", + "august", + "aunt", + "austere", + "autumn", + "avatar", + "avidly", + "avoid", + "awakened", + "awesome", + "awful", + "awkward", + "awning", + "awoken", + "axes", + "axis", + "axle", + "aztec", + "azure", + "baby", + "bacon", + "badge", + "baffles", + "bagpipe", + "bailed", + "bakery", + "balding", + "bamboo", + "banjo", + "baptism", + "basin", + "batch", + "bawled", + "bays", + "because", + "beer", + "befit", + "begun", + "behind", + "being", + "below", + "bemused", + "benches", + "berries", + "bested", + "betting", + "bevel", + "beware", + "beyond", + "bias", + "bicycle", + "bids", + "bifocals", + "biggest", + "bikini", + "bimonthly", + "binocular", + "biology", + "biplane", + "birth", + "biscuit", + "bite", + "biweekly", + "blender", + "blip", + "bluntly", + "boat", + "bobsled", + "bodies", + "bogeys", + "boil", + "boldly", + "bomb", + "border", + "boss", + "both", + "bounced", + "bovine", + "bowling", + "boxes", + "boyfriend", + "broken", + "brunt", + "bubble", + "buckets", + "budget", + "buffet", + "bugs", + "building", + "bulb", + "bumper", + "bunch", + "business", + "butter", + "buying", + "buzzer", + "bygones", + "byline", + "bypass", + "cabin", + "cactus", + "cadets", + "cafe", + "cage", + "cajun", + "cake", + "calamity", + "camp", + "candy", + "casket", + "catch", + "cause", + "cavernous", + "cease", + "cedar", + "ceiling", + "cell", + "cement", + "cent", + "certain", + "chlorine", + "chrome", + "cider", + "cigar", + "cinema", + "circle", + "cistern", + "citadel", + "civilian", + "claim", + "click", + "clue", + "coal", + "cobra", + "cocoa", + "code", + "coexist", + "coffee", + "cogs", + "cohesive", + "coils", + "colony", + "comb", + "cool", + "copy", + "corrode", + "costume", + "cottage", + "cousin", + "cowl", + "criminal", + "cube", + "cucumber", + "cuddled", + "cuffs", + "cuisine", + "cunning", + "cupcake", + "custom", + "cycling", + "cylinder", + "cynical", + "dabbing", + "dads", + "daft", + "dagger", + "daily", + "damp", + "dangerous", + "dapper", + "darted", + "dash", + "dating", + "dauntless", + "dawn", + "daytime", + "dazed", + "debut", + "decay", + "dedicated", + "deepest", + "deftly", + "degrees", + "dehydrate", + "deity", + "dejected", + "delayed", + "demonstrate", + "dented", + "deodorant", + "depth", + "desk", + "devoid", + "dewdrop", + "dexterity", + "dialect", + "dice", + "diet", + "different", + "digit", + "dilute", + "dime", + "dinner", + "diode", + "diplomat", + "directed", + "distance", + "ditch", + "divers", + "dizzy", + "doctor", + "dodge", + "does", + "dogs", + "doing", + "dolphin", + "domestic", + "donuts", + "doorway", + "dormant", + "dosage", + "dotted", + "double", + "dove", + "down", + "dozen", + "dreams", + "drinks", + "drowning", + "drunk", + "drying", + "dual", + "dubbed", + "duckling", + "dude", + "duets", + "duke", + "dullness", + "dummy", + "dunes", + "duplex", + "duration", + "dusted", + "duties", + "dwarf", + "dwelt", + "dwindling", + "dying", + "dynamite", + "dyslexic", + "each", + "eagle", + "earth", + "easy", + "eating", + "eavesdrop", + "eccentric", + "echo", + "eclipse", + "economics", + "ecstatic", + "eden", + "edgy", + "edited", + "educated", + "eels", + "efficient", + "eggs", + "egotistic", + "eight", + "either", + "eject", + "elapse", + "elbow", + "eldest", + "eleven", + "elite", + "elope", + "else", + "eluded", + "emails", + "ember", + "emerge", + "emit", + "emotion", + "empty", + "emulate", + "energy", + "enforce", + "enhanced", + "enigma", + "enjoy", + "enlist", + "enmity", + "enough", + "enraged", + "ensign", + "entrance", + "envy", + "epoxy", + "equip", + "erase", + "erected", + "erosion", + "error", + "eskimos", + "espionage", + "essential", + "estate", + "etched", + "eternal", + "ethics", + "etiquette", + "evaluate", + "evenings", + "evicted", + "evolved", + "examine", + "excess", + "exhale", + "exit", + "exotic", + "exquisite", + "extra", + "exult", + "fabrics", + "factual", + "fading", + "fainted", + "faked", + "fall", + "family", + "fancy", + "farming", + "fatal", + "faulty", + "fawns", + "faxed", + "fazed", + "feast", + "february", + "federal", + "feel", + "feline", + "females", + "fences", + "ferry", + "festival", + "fetches", + "fever", + "fewest", + "fiat", + "fibula", + "fictional", + "fidget", + "fierce", + "fifteen", + "fight", + "films", + "firm", + "fishing", + "fitting", + "five", + "fixate", + "fizzle", + "fleet", + "flippant", + "flying", + "foamy", + "focus", + "foes", + "foggy", + "foiled", + "folding", + "fonts", + "foolish", + "fossil", + "fountain", + "fowls", + "foxes", + "foyer", + "framed", + "friendly", + "frown", + "fruit", + "frying", + "fudge", + "fuel", + "fugitive", + "fully", + "fuming", + "fungal", + "furnished", + "fuselage", + "future", + "fuzzy", + "gables", + "gadget", + "gags", + "gained", + "galaxy", + "gambit", + "gang", + "gasp", + "gather", + "gauze", + "gave", + "gawk", + "gaze", + "gearbox", + "gecko", + "geek", + "gels", + "gemstone", + "general", + "geometry", + "germs", + "gesture", + "getting", + "geyser", + "ghetto", + "ghost", + "giant", + "giddy", + "gifts", + "gigantic", + "gills", + "gimmick", + "ginger", + "girth", + "giving", + "glass", + "gleeful", + "glide", + "gnaw", + "gnome", + "goat", + "goblet", + "godfather", + "goes", + "goggles", + "going", + "goldfish", + "gone", + "goodbye", + "gopher", + "gorilla", + "gossip", + "gotten", + "gourmet", + "governing", + "gown", + "greater", + "grunt", + "guarded", + "guest", + "guide", + "gulp", + "gumball", + "guru", + "gusts", + "gutter", + "guys", + "gymnast", + "gypsy", + "gyrate", + "habitat", + "hacksaw", + "haggled", + "hairy", + "hamburger", + "happens", + "hashing", + "hatchet", + "haunted", + "having", + "hawk", + "haystack", + "hazard", + "hectare", + "hedgehog", + "heels", + "hefty", + "height", + "hemlock", + "hence", + "heron", + "hesitate", + "hexagon", + "hickory", + "hiding", + "highway", + "hijack", + "hiker", + "hills", + "himself", + "hinder", + "hippo", + "hire", + "history", + "hitched", + "hive", + "hoax", + "hobby", + "hockey", + "hoisting", + "hold", + "honked", + "hookup", + "hope", + "hornet", + "hospital", + "hotel", + "hounded", + "hover", + "howls", + "hubcaps", + "huddle", + "huge", + "hull", + "humid", + "hunter", + "hurried", + "husband", + "huts", + "hybrid", + "hydrogen", + "hyper", + "iceberg", + "icing", + "icon", + "identity", + "idiom", + "idled", + "idols", + "igloo", + "ignore", + "iguana", + "illness", + "imagine", + "imbalance", + "imitate", + "impel", + "inactive", + "inbound", + "incur", + "industrial", + "inexact", + "inflamed", + "ingested", + "initiate", + "injury", + "inkling", + "inline", + "inmate", + "innocent", + "inorganic", + "input", + "inquest", + "inroads", + "insult", + "intended", + "inundate", + "invoke", + "inwardly", + "ionic", + "irate", + "iris", + "irony", + "irritate", + "island", + "isolated", + "issued", + "italics", + "itches", + "items", + "itinerary", + "itself", + "ivory", + "jabbed", + "jackets", + "jaded", + "jagged", + "jailed", + "jamming", + "january", + "jargon", + "jaunt", + "javelin", + "jaws", + "jazz", + "jeans", + "jeers", + "jellyfish", + "jeopardy", + "jerseys", + "jester", + "jetting", + "jewels", + "jigsaw", + "jingle", + "jittery", + "jive", + "jobs", + "jockey", + "jogger", + "joining", + "joking", + "jolted", + "jostle", + "journal", + "joyous", + "jubilee", + "judge", + "juggled", + "juicy", + "jukebox", + "july", + "jump", + "junk", + "jury", + "justice", + "juvenile", + "kangaroo", + "karate", + "keep", + "kennel", + "kept", + "kernels", + "kettle", + "keyboard", + "kickoff", + "kidneys", + "king", + "kiosk", + "kisses", + "kitchens", + "kiwi", + "knapsack", + "knee", + "knife", + "knowledge", + "knuckle", + "koala", + "laboratory", + "ladder", + "lagoon", + "lair", + "lakes", + "lamb", + "language", + "laptop", + "large", + "last", + "later", + "launching", + "lava", + "lawsuit", + "layout", + "lazy", + "lectures", + "ledge", + "leech", + "left", + "legion", + "leisure", + "lemon", + "lending", + "leopard", + "lesson", + "lettuce", + "lexicon", + "liar", + "library", + "licks", + "lids", + "lied", + "lifestyle", + "light", + "likewise", + "lilac", + "limits", + "linen", + "lion", + "lipstick", + "liquid", + "listen", + "lively", + "loaded", + "lobster", + "locker", + "lodge", + "lofty", + "logic", + "loincloth", + "long", + "looking", + "lopped", + "lordship", + "losing", + "lottery", + "loudly", + "love", + "lower", + "loyal", + "lucky", + "luggage", + "lukewarm", + "lullaby", + "lumber", + "lunar", + "lurk", + "lush", + "luxury", + "lymph", + "lynx", + "lyrics", + "macro", + "madness", + "magically", + "mailed", + "major", + "makeup", + "malady", + "mammal", + "maps", + "masterful", + "match", + "maul", + "maverick", + "maximum", + "mayor", + "maze", + "meant", + "mechanic", + "medicate", + "meeting", + "megabyte", + "melting", + "memoir", + "menu", + "merger", + "mesh", + "metro", + "mews", + "mice", + "midst", + "mighty", + "mime", + "mirror", + "misery", + "mittens", + "mixture", + "moat", + "mobile", + "mocked", + "mohawk", + "moisture", + "molten", + "moment", + "money", + "moon", + "mops", + "morsel", + "mostly", + "motherly", + "mouth", + "movement", + "mowing", + "much", + "muddy", + "muffin", + "mugged", + "mullet", + "mumble", + "mundane", + "muppet", + "mural", + "musical", + "muzzle", + "myriad", + "mystery", + "myth", + "nabbing", + "nagged", + "nail", + "names", + "nanny", + "napkin", + "narrate", + "nasty", + "natural", + "nautical", + "navy", + "nearby", + "necklace", + "needed", + "negative", + "neither", + "neon", + "nephew", + "nerves", + "nestle", + "network", + "neutral", + "never", + "newt", + "nexus", + "nibs", + "niche", + "niece", + "nifty", + "nightly", + "nimbly", + "nineteen", + "nirvana", + "nitrogen", + "nobody", + "nocturnal", + "nodes", + "noises", + "nomad", + "noodles", + "northern", + "nostril", + "noted", + "nouns", + "novelty", + "nowhere", + "nozzle", + "nuance", + "nucleus", + "nudged", + "nugget", + "nuisance", + "null", + "number", + "nuns", + "nurse", + "nutshell", + "nylon", + "oaks", + "oars", + "oasis", + "oatmeal", + "obedient", + "object", + "obliged", + "obnoxious", + "observant", + "obtains", + "obvious", + "occur", + "ocean", + "october", + "odds", + "odometer", + "offend", + "often", + "oilfield", + "ointment", + "okay", + "older", + "olive", + "olympics", + "omega", + "omission", + "omnibus", + "onboard", + "oncoming", + "oneself", + "ongoing", + "onion", + "online", + "onslaught", + "onto", + "onward", + "oozed", + "opacity", + "opened", + "opposite", + "optical", + "opus", + "orange", + "orbit", + "orchid", + "orders", + "organs", + "origin", + "ornament", + "orphans", + "oscar", + "ostrich", + "otherwise", + "otter", + "ouch", + "ought", + "ounce", + "ourselves", + "oust", + "outbreak", + "oval", + "oven", + "owed", + "owls", + "owner", + "oxidant", + "oxygen", + "oyster", + "ozone", + "pact", + "paddles", + "pager", + "pairing", + "palace", + "pamphlet", + "pancakes", + "paper", + "paradise", + "pastry", + "patio", + "pause", + "pavements", + "pawnshop", + "payment", + "peaches", + "pebbles", + "peculiar", + "pedantic", + "peeled", + "pegs", + "pelican", + "pencil", + "people", + "pepper", + "perfect", + "pests", + "petals", + "phase", + "pheasants", + "phone", + "phrases", + "physics", + "piano", + "picked", + "pierce", + "pigment", + "piloted", + "pimple", + "pinched", + "pioneer", + "pipeline", + "pirate", + "pistons", + "pitched", + "pivot", + "pixels", + "pizza", + "playful", + "pledge", + "pliers", + "plotting", + "plus", + "plywood", + "poaching", + "pockets", + "podcast", + "poetry", + "point", + "poker", + "polar", + "ponies", + "pool", + "popular", + "portents", + "possible", + "potato", + "pouch", + "poverty", + "powder", + "pram", + "present", + "pride", + "problems", + "pruned", + "prying", + "psychic", + "public", + "puck", + "puddle", + "puffin", + "pulp", + "pumpkins", + "punch", + "puppy", + "purged", + "push", + "putty", + "puzzled", + "pylons", + "pyramid", + "python", + "queen", + "quick", + "quote", + "rabbits", + "racetrack", + "radar", + "rafts", + "rage", + "railway", + "raking", + "rally", + "ramped", + "randomly", + "rapid", + "rarest", + "rash", + "rated", + "ravine", + "rays", + "razor", + "react", + "rebel", + "recipe", + "reduce", + "reef", + "refer", + "regular", + "reheat", + "reinvest", + "rejoices", + "rekindle", + "relic", + "remedy", + "renting", + "reorder", + "repent", + "request", + "reruns", + "rest", + "return", + "reunion", + "revamp", + "rewind", + "rhino", + "rhythm", + "ribbon", + "richly", + "ridges", + "rift", + "rigid", + "rims", + "ringing", + "riots", + "ripped", + "rising", + "ritual", + "river", + "roared", + "robot", + "rockets", + "rodent", + "rogue", + "roles", + "romance", + "roomy", + "roped", + "roster", + "rotate", + "rounded", + "rover", + "rowboat", + "royal", + "ruby", + "rudely", + "ruffled", + "rugged", + "ruined", + "ruling", + "rumble", + "runway", + "rural", + "rustled", + "ruthless", + "sabotage", + "sack", + "sadness", + "safety", + "saga", + "sailor", + "sake", + "salads", + "sample", + "sanity", + "sapling", + "sarcasm", + "sash", + "satin", + "saucepan", + "saved", + "sawmill", + "saxophone", + "sayings", + "scamper", + "scenic", + "school", + "science", + "scoop", + "scrub", + "scuba", + "seasons", + "second", + "sedan", + "seeded", + "segments", + "seismic", + "selfish", + "semifinal", + "sensible", + "september", + "sequence", + "serving", + "session", + "setup", + "seventh", + "sewage", + "shackles", + "shelter", + "shipped", + "shocking", + "shrugged", + "shuffled", + "shyness", + "siblings", + "sickness", + "sidekick", + "sieve", + "sifting", + "sighting", + "silk", + "simplest", + "sincerely", + "sipped", + "siren", + "situated", + "sixteen", + "sizes", + "skater", + "skew", + "skirting", + "skulls", + "skydive", + "slackens", + "sleepless", + "slid", + "slower", + "slug", + "smash", + "smelting", + "smidgen", + "smog", + "smuggled", + "snake", + "sneeze", + "sniff", + "snout", + "snug", + "soapy", + "sober", + "soccer", + "soda", + "software", + "soggy", + "soil", + "solved", + "somewhere", + "sonic", + "soothe", + "soprano", + "sorry", + "southern", + "sovereign", + "sowed", + "soya", + "space", + "speedy", + "sphere", + "spiders", + "splendid", + "spout", + "sprig", + "spud", + "spying", + "square", + "stacking", + "stellar", + "stick", + "stockpile", + "strained", + "stunning", + "stylishly", + "subtly", + "succeed", + "suddenly", + "suede", + "suffice", + "sugar", + "suitcase", + "sulking", + "summon", + "sunken", + "superior", + "surfer", + "sushi", + "suture", + "swagger", + "swept", + "swiftly", + "sword", + "swung", + "syllabus", + "symptoms", + "syndrome", + "syringe", + "system", + "taboo", + "tacit", + "tadpoles", + "tagged", + "tail", + "taken", + "talent", + "tamper", + "tanks", + "tapestry", + "tarnished", + "tasked", + "tattoo", + "taunts", + "tavern", + "tawny", + "taxi", + "teardrop", + "technical", + "tedious", + "teeming", + "tell", + "template", + "tender", + "tepid", + "tequila", + "terminal", + "testing", + "tether", + "textbook", + "thaw", + "theatrics", + "thirsty", + "thorn", + "threaten", + "thumbs", + "thwart", + "ticket", + "tidy", + "tiers", + "tiger", + "tilt", + "timber", + "tinted", + "tipsy", + "tirade", + "tissue", + "titans", + "toaster", + "tobacco", + "today", + "toenail", + "toffee", + "together", + "toilet", + "token", + "tolerant", + "tomorrow", + "tonic", + "toolbox", + "topic", + "torch", + "tossed", + "total", + "touchy", + "towel", + "toxic", + "toyed", + "trash", + "trendy", + "tribal", + "trolling", + "truth", + "trying", + "tsunami", + "tubes", + "tucks", + "tudor", + "tuesday", + "tufts", + "tugs", + "tuition", + "tulips", + "tumbling", + "tunnel", + "turnip", + "tusks", + "tutor", + "tuxedo", + "twang", + "tweezers", + "twice", + "twofold", + "tycoon", + "typist", + "tyrant", + "ugly", + "ulcers", + "ultimate", + "umbrella", + "umpire", + "unafraid", + "unbending", + "uncle", + "under", + "uneven", + "unfit", + "ungainly", + "unhappy", + "union", + "unjustly", + "unknown", + "unlikely", + "unmask", + "unnoticed", + "unopened", + "unplugs", + "unquoted", + "unrest", + "unsafe", + "until", + "unusual", + "unveil", + "unwind", + "unzip", + "upbeat", + "upcoming", + "update", + "upgrade", + "uphill", + "upkeep", + "upload", + "upon", + "upper", + "upright", + "upstairs", + "uptight", + "upwards", + "urban", + "urchins", + "urgent", + "usage", + "useful", + "usher", + "using", + "usual", + "utensils", + "utility", + "utmost", + "utopia", + "uttered", + "vacation", + "vague", + "vain", + "value", + "vampire", + "vane", + "vapidly", + "vary", + "vastness", + "vats", + "vaults", + "vector", + "veered", + "vegan", + "vehicle", + "vein", + "velvet", + "venomous", + "verification", + "vessel", + "veteran", + "vexed", + "vials", + "vibrate", + "victim", + "video", + "viewpoint", + "vigilant", + "viking", + "village", + "vinegar", + "violin", + "vipers", + "virtual", + "visited", + "vitals", + "vivid", + "vixen", + "vocal", + "vogue", + "voice", + "volcano", + "vortex", + "voted", + "voucher", + "vowels", + "voyage", + "vulture", + "wade", + "waffle", + "wagtail", + "waist", + "waking", + "wallets", + "wanted", + "warped", + "washing", + "water", + "waveform", + "waxing", + "wayside", + "weavers", + "website", + "wedge", + "weekday", + "weird", + "welders", + "went", + "wept", + "were", + "western", + "wetsuit", + "whale", + "when", + "whipped", + "whole", + "wickets", + "width", + "wield", + "wife", + "wiggle", + "wildly", + "winter", + "wipeout", + "wiring", + "wise", + "withdrawn", + "wives", + "wizard", + "wobbly", + "woes", + "woken", + "wolf", + "womanly", + "wonders", + "woozy", + "worry", + "wounded", + "woven", + "wrap", + "wrist", + "wrong", + "yacht", + "yahoo", + "yanks", + "yard", + "yawning", + "yearbook", + "yellow", + "yesterday", + "yeti", + "yields", + "yodel", + "yoga", + "younger", + "yoyo", + "zapped", + "zeal", + "zebra", + "zero", + "zesty", + "zigzags", + "zinger", + "zippers", + "zodiac", + "zombie", + "zones", + "zoom" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/eo.json b/coins/monero/src/wallet/seed/classic/eo.json new file mode 100644 index 00000000..9ed90934 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/eo.json @@ -0,0 +1,1628 @@ +[ + "abako", + "abdiki", + "abelo", + "abituriento", + "ablativo", + "abnorma", + "abonantoj", + "abrikoto", + "absoluta", + "abunda", + "acetono", + "acida", + "adapti", + "adekvata", + "adheri", + "adicii", + "adjektivo", + "administri", + "adolesko", + "adreso", + "adstringa", + "adulto", + "advokato", + "adzo", + "aeroplano", + "aferulo", + "afgana", + "afiksi", + "aflaba", + "aforismo", + "afranki", + "aftozo", + "afusto", + "agavo", + "agento", + "agiti", + "aglo", + "agmaniero", + "agnoski", + "agordo", + "agrabla", + "agtipo", + "agutio", + "aikido", + "ailanto", + "aina", + "ajatolo", + "ajgenvaloro", + "ajlobulbo", + "ajnlitera", + "ajuto", + "ajzi", + "akademio", + "akcepti", + "akeo", + "akiri", + "aklamado", + "akmeo", + "akno", + "akompani", + "akrobato", + "akselo", + "aktiva", + "akurata", + "akvofalo", + "alarmo", + "albumo", + "alcedo", + "aldoni", + "aleo", + "alfabeto", + "algo", + "alhasti", + "aligatoro", + "alkoholo", + "almozo", + "alnomo", + "alojo", + "alpinisto", + "alrigardi", + "alskribi", + "alta", + "alumeto", + "alveni", + "alzaca", + "amaso", + "ambasado", + "amdeklaro", + "amebo", + "amfibio", + "amhara", + "amiko", + "amkanto", + "amletero", + "amnestio", + "amoranto", + "amplekso", + "amrakonto", + "amsterdama", + "amuzi", + "ananaso", + "androido", + "anekdoto", + "anfrakto", + "angulo", + "anheli", + "animo", + "anjono", + "ankro", + "anonci", + "anpriskribo", + "ansero", + "antikva", + "anuitato", + "aorto", + "aparta", + "aperti", + "apika", + "aplikado", + "apneo", + "apogi", + "aprobi", + "apsido", + "apterigo", + "apudesto", + "araneo", + "arbo", + "ardeco", + "aresti", + "argilo", + "aristokrato", + "arko", + "arlekeno", + "armi", + "arniko", + "aromo", + "arpio", + "arsenalo", + "artisto", + "aruba", + "arvorto", + "asaio", + "asbesto", + "ascendi", + "asekuri", + "asfalto", + "asisti", + "askalono", + "asocio", + "aspekti", + "astro", + "asulo", + "atakonto", + "atendi", + "atingi", + "atleto", + "atmosfero", + "atomo", + "atropino", + "atuto", + "avataro", + "aventuro", + "aviadilo", + "avokado", + "azaleo", + "azbuko", + "azenino", + "azilpetanto", + "azoto", + "azteka", + "babili", + "bacilo", + "badmintono", + "bagatelo", + "bahama", + "bajoneto", + "baki", + "balai", + "bambuo", + "bani", + "baobabo", + "bapti", + "baro", + "bastono", + "batilo", + "bavara", + "bazalto", + "beata", + "bebofono", + "bedo", + "begonio", + "behaviorismo", + "bejlo", + "bekero", + "belarto", + "bemolo", + "benko", + "bereto", + "besto", + "betulo", + "bevelo", + "bezoni", + "biaso", + "biblioteko", + "biciklo", + "bidaro", + "bieno", + "bifsteko", + "bigamiulo", + "bijekcio", + "bikino", + "bildo", + "bimetalismo", + "bindi", + "biografio", + "birdo", + "biskvito", + "bitlibro", + "bivako", + "bizara", + "bjalistoka", + "blanka", + "bleki", + "blinda", + "blovi", + "blua", + "boato", + "bobsledo", + "bocvanano", + "bodisatvo", + "bofratino", + "bogefratoj", + "bohema", + "boji", + "bokalo", + "boli", + "bombono", + "bona", + "bopatrino", + "bordo", + "bosko", + "botelo", + "bovido", + "brakpleno", + "bretaro", + "brikmuro", + "broso", + "brulema", + "bubalo", + "buctrapi", + "budo", + "bufedo", + "bugio", + "bujabeso", + "buklo", + "buldozo", + "bumerango", + "bunta", + "burokrataro", + "busbileto", + "butero", + "buzuko", + "caro", + "cebo", + "ceceo", + "cedro", + "cefalo", + "cejana", + "cekumo", + "celebri", + "cemento", + "cent", + "cepo", + "certa", + "cetera", + "cezio", + "ciano", + "cibeto", + "cico", + "cidro", + "cifero", + "cigaredo", + "ciklo", + "cilindro", + "cimbalo", + "cinamo", + "cipreso", + "cirkonstanco", + "cisterno", + "citrono", + "ciumi", + "civilizado", + "colo", + "congo", + "cunamo", + "cvana", + "dabi", + "daco", + "dadaismo", + "dafodilo", + "dago", + "daimio", + "dajmono", + "daktilo", + "dalio", + "damo", + "danki", + "darmo", + "datumoj", + "dazipo", + "deadmoni", + "debeto", + "decidi", + "dedukti", + "deerigi", + "defendi", + "degeli", + "dehaki", + "deirpunkto", + "deklaracio", + "delikata", + "demandi", + "dento", + "dependi", + "derivi", + "desegni", + "detrui", + "devi", + "deziri", + "dialogo", + "dicentro", + "didaktika", + "dieto", + "diferenci", + "digesti", + "diino", + "dikfingro", + "diligenta", + "dimensio", + "dinamo", + "diodo", + "diplomo", + "direkte", + "diskuti", + "diurno", + "diversa", + "dizajno", + "dobrogitaro", + "docento", + "dogano", + "dojeno", + "doktoro", + "dolori", + "domego", + "donaci", + "dopado", + "dormi", + "dosierujo", + "dotita", + "dozeno", + "drato", + "dresi", + "drinki", + "droni", + "druido", + "duaranga", + "dubi", + "ducent", + "dudek", + "duelo", + "dufoje", + "dugongo", + "duhufa", + "duilo", + "dujare", + "dukato", + "duloka", + "dumtempe", + "dungi", + "duobla", + "dupiedulo", + "dura", + "dusenca", + "dutaga", + "duuma", + "duvalvuloj", + "duzo", + "ebena", + "eblecoj", + "ebono", + "ebria", + "eburo", + "ecaro", + "ecigi", + "ecoj", + "edelvejso", + "editoro", + "edro", + "eduki", + "edzino", + "efektiva", + "efiki", + "efloreski", + "egala", + "egeco", + "egiptologo", + "eglefino", + "egoista", + "egreto", + "ejakuli", + "ejlo", + "ekarto", + "ekbruligi", + "ekceli", + "ekde", + "ekesti", + "ekfirmao", + "ekgliti", + "ekhavi", + "ekipi", + "ekkapti", + "eklezio", + "ekmalsati", + "ekonomio", + "ekpluvi", + "ekrano", + "ekster", + "ektiri", + "ekumeno", + "ekvilibro", + "ekzemplo", + "elasta", + "elbalai", + "elcento", + "eldoni", + "elektro", + "elfari", + "elgliti", + "elhaki", + "elipso", + "elkovi", + "ellasi", + "elmeti", + "elnutri", + "elokventa", + "elparoli", + "elrevigi", + "elstari", + "elteni", + "eluzita", + "elvoki", + "elzasa", + "emajlo", + "embaraso", + "emerito", + "emfazo", + "eminenta", + "emocio", + "empiria", + "emulsio", + "enarkivigi", + "enboteligi", + "enciklopedio", + "endorfino", + "energio", + "enfermi", + "engluti", + "enhavo", + "enigmo", + "enjekcio", + "enketi", + "enlanda", + "enmeti", + "enorma", + "enplanti", + "enradiki", + "enspezo", + "entrepreni", + "enui", + "envolvi", + "enzimo", + "eono", + "eosto", + "epitafo", + "epoko", + "epriskribebla", + "epsilono", + "erari", + "erbio", + "erco", + "erekti", + "ergonomia", + "erikejo", + "ermito", + "erotika", + "erpilo", + "erupcio", + "esameno", + "escepti", + "esenco", + "eskapi", + "esotera", + "esperi", + "estonto", + "etapo", + "etendi", + "etfingro", + "etikedo", + "etlitero", + "etmakleristo", + "etnika", + "etoso", + "etradio", + "etskala", + "etullernejo", + "evakui", + "evento", + "eviti", + "evolui", + "ezoko", + "fabriko", + "facila", + "fadeno", + "fagoto", + "fajro", + "fakto", + "fali", + "familio", + "fanatiko", + "farbo", + "fasko", + "fatala", + "favora", + "fazeolo", + "febro", + "federacio", + "feino", + "fekunda", + "felo", + "femuro", + "fenestro", + "fermi", + "festi", + "fetora", + "fezo", + "fiasko", + "fibro", + "fidela", + "fiera", + "fifama", + "figuro", + "fiherbo", + "fiinsekto", + "fiksa", + "filmo", + "fimensa", + "finalo", + "fiolo", + "fiparoli", + "firmao", + "fisko", + "fitingo", + "fiuzanto", + "fivorto", + "fiziko", + "fjordo", + "flago", + "flegi", + "flirti", + "floro", + "flugi", + "fobio", + "foceno", + "foirejo", + "fojfoje", + "fokuso", + "folio", + "fomenti", + "fonto", + "formulo", + "fosforo", + "fotografi", + "fratino", + "fremda", + "friti", + "frosto", + "frua", + "ftizo", + "fuelo", + "fugo", + "fuksia", + "fulmilo", + "fumanto", + "fundamento", + "fuorto", + "furioza", + "fusilo", + "futbalo", + "fuzio", + "gabardino", + "gado", + "gaela", + "gafo", + "gagato", + "gaja", + "gaki", + "galanta", + "gamao", + "ganto", + "gapulo", + "gardi", + "gasto", + "gavio", + "gazeto", + "geamantoj", + "gebani", + "geedzeco", + "gefratoj", + "geheno", + "gejsero", + "geko", + "gelateno", + "gemisto", + "geniulo", + "geografio", + "gepardo", + "geranio", + "gestolingvo", + "geto", + "geumo", + "gibono", + "giganta", + "gildo", + "gimnastiko", + "ginekologo", + "gipsi", + "girlando", + "gistfungo", + "gitaro", + "glazuro", + "glebo", + "gliti", + "globo", + "gluti", + "gnafalio", + "gnejso", + "gnomo", + "gnuo", + "gobio", + "godetio", + "goeleto", + "gojo", + "golfludejo", + "gombo", + "gondolo", + "gorilo", + "gospelo", + "gotika", + "granda", + "greno", + "griza", + "groto", + "grupo", + "guano", + "gubernatoro", + "gudrotuko", + "gufo", + "gujavo", + "guldeno", + "gumi", + "gupio", + "guruo", + "gusto", + "guto", + "guvernistino", + "gvardio", + "gverilo", + "gvidanto", + "habitato", + "hadito", + "hafnio", + "hagiografio", + "haitiano", + "hajlo", + "hakbloko", + "halti", + "hamstro", + "hangaro", + "hapalo", + "haro", + "hasta", + "hati", + "havebla", + "hazardo", + "hebrea", + "hedero", + "hegemonio", + "hejmo", + "hektaro", + "helpi", + "hemisfero", + "heni", + "hepato", + "herbo", + "hesa", + "heterogena", + "heziti", + "hiacinto", + "hibrida", + "hidrogeno", + "hieroglifo", + "higieno", + "hihii", + "hilumo", + "himno", + "hindino", + "hiperteksto", + "hirundo", + "historio", + "hobio", + "hojli", + "hokeo", + "hologramo", + "homido", + "honesta", + "hopi", + "horizonto", + "hospitalo", + "hotelo", + "huadi", + "hubo", + "hufumo", + "hugenoto", + "hukero", + "huligano", + "humana", + "hundo", + "huoj", + "hupilo", + "hurai", + "husaro", + "hutuo", + "huzo", + "iafoje", + "iagrade", + "iamaniere", + "iarelate", + "iaspeca", + "ibekso", + "ibiso", + "idaro", + "ideala", + "idiomo", + "idolo", + "iele", + "igluo", + "ignori", + "iguamo", + "igvano", + "ikono", + "iksodo", + "ikto", + "iliaflanke", + "ilkomputilo", + "ilobreto", + "ilremedo", + "ilumini", + "imagi", + "imitado", + "imperio", + "imuna", + "incidento", + "industrio", + "inerta", + "infano", + "ingenra", + "inhali", + "iniciati", + "injekti", + "inklino", + "inokuli", + "insekto", + "inteligenta", + "inundi", + "inviti", + "ioma", + "ionosfero", + "iperito", + "ipomeo", + "irana", + "irejo", + "irigacio", + "ironio", + "isato", + "islamo", + "istempo", + "itinero", + "itrio", + "iuloke", + "iumaniere", + "iutempe", + "izolita", + "jado", + "jaguaro", + "jakto", + "jama", + "januaro", + "japano", + "jarringo", + "jazo", + "jenoj", + "jesulo", + "jetavio", + "jezuito", + "jodli", + "joviala", + "juano", + "jubileo", + "judismo", + "jufto", + "juki", + "julio", + "juneca", + "jupo", + "juristo", + "juste", + "juvelo", + "kabineto", + "kadrato", + "kafo", + "kahelo", + "kajako", + "kakao", + "kalkuli", + "kampo", + "kanti", + "kapitalo", + "karaktero", + "kaserolo", + "katapulto", + "kaverna", + "kazino", + "kebabo", + "kefiro", + "keglo", + "kejlo", + "kekso", + "kelka", + "kemio", + "kerno", + "kesto", + "kiamaniere", + "kibuco", + "kidnapi", + "kielo", + "kikero", + "kilogramo", + "kimono", + "kinejo", + "kiosko", + "kirurgo", + "kisi", + "kitelo", + "kivio", + "klavaro", + "klerulo", + "klini", + "klopodi", + "klubo", + "knabo", + "knedi", + "koalo", + "kobalto", + "kodigi", + "kofro", + "kohera", + "koincidi", + "kojoto", + "kokoso", + "koloro", + "komenci", + "kontrakto", + "kopio", + "korekte", + "kosti", + "kotono", + "kovri", + "krajono", + "kredi", + "krii", + "krom", + "kruco", + "ksantino", + "ksenono", + "ksilofono", + "ksosa", + "kubuto", + "kudri", + "kuglo", + "kuiri", + "kuko", + "kulero", + "kumuluso", + "kuneco", + "kupro", + "kuri", + "kuseno", + "kutimo", + "kuvo", + "kuzino", + "kvalito", + "kverko", + "kvin", + "kvoto", + "labori", + "laculo", + "ladbotelo", + "lafo", + "laguno", + "laikino", + "laktobovino", + "lampolumo", + "landkarto", + "laosa", + "lapono", + "larmoguto", + "lastjare", + "latitudo", + "lavejo", + "lazanjo", + "leciono", + "ledosako", + "leganto", + "lekcio", + "lemura", + "lentuga", + "leopardo", + "leporo", + "lerni", + "lesivo", + "letero", + "levilo", + "lezi", + "liano", + "libera", + "liceo", + "lieno", + "lifto", + "ligilo", + "likvoro", + "lila", + "limono", + "lingvo", + "lipo", + "lirika", + "listo", + "literatura", + "liveri", + "lobio", + "logika", + "lojala", + "lokalo", + "longa", + "lordo", + "lotado", + "loza", + "luanto", + "lubriki", + "lucida", + "ludema", + "luigi", + "lukso", + "luli", + "lumbilda", + "lunde", + "lupago", + "lustro", + "lutilo", + "luzerno", + "maato", + "maceri", + "madono", + "mafiano", + "magazeno", + "mahometano", + "maizo", + "majstro", + "maketo", + "malgranda", + "mamo", + "mandareno", + "maorio", + "mapigi", + "marini", + "masko", + "mateno", + "mazuto", + "meandro", + "meblo", + "mecenato", + "medialo", + "mefito", + "megafono", + "mejlo", + "mekanika", + "melodia", + "membro", + "mendi", + "mergi", + "mespilo", + "metoda", + "mevo", + "mezuri", + "miaflanke", + "micelio", + "mielo", + "migdalo", + "mikrofilmo", + "militi", + "mimiko", + "mineralo", + "miopa", + "miri", + "mistera", + "mitralo", + "mizeri", + "mjelo", + "mnemoniko", + "mobilizi", + "mocio", + "moderna", + "mohajro", + "mokadi", + "molaro", + "momento", + "monero", + "mopso", + "mordi", + "moskito", + "motoro", + "movimento", + "mozaiko", + "mueli", + "mukozo", + "muldi", + "mumio", + "munti", + "muro", + "muskolo", + "mutacio", + "muzikisto", + "nabo", + "nacio", + "nadlo", + "nafto", + "naiva", + "najbaro", + "nanometro", + "napo", + "narciso", + "naski", + "naturo", + "navigi", + "naztruo", + "neatendite", + "nebulo", + "necesa", + "nedankinde", + "neebla", + "nefari", + "negoco", + "nehavi", + "neimagebla", + "nektaro", + "nelonga", + "nematura", + "nenia", + "neordinara", + "nepra", + "nervuro", + "nesto", + "nete", + "neulo", + "nevino", + "nifo", + "nigra", + "nihilisto", + "nikotino", + "nilono", + "nimfeo", + "nitrogeno", + "nivelo", + "nobla", + "nocio", + "nodozo", + "nokto", + "nomkarto", + "norda", + "nostalgio", + "notbloko", + "novico", + "nuanco", + "nuboza", + "nuda", + "nugato", + "nuklea", + "nuligi", + "numero", + "nuntempe", + "nupto", + "nura", + "nutri", + "oazo", + "obei", + "objekto", + "oblikva", + "obolo", + "observi", + "obtuza", + "obuso", + "oceano", + "odekolono", + "odori", + "oferti", + "oficiala", + "ofsajdo", + "ofte", + "ogivo", + "ogro", + "ojstredoj", + "okaze", + "okcidenta", + "okro", + "oksido", + "oktobro", + "okulo", + "oldulo", + "oleo", + "olivo", + "omaro", + "ombro", + "omego", + "omikrono", + "omleto", + "omnibuso", + "onagro", + "ondo", + "oneco", + "onidire", + "onklino", + "onlajna", + "onomatopeo", + "ontologio", + "opaka", + "operacii", + "opinii", + "oportuna", + "opresi", + "optimisto", + "oratoro", + "orbito", + "ordinara", + "orelo", + "orfino", + "organizi", + "orienta", + "orkestro", + "orlo", + "orminejo", + "ornami", + "ortangulo", + "orumi", + "oscedi", + "osmozo", + "ostocerbo", + "ovalo", + "ovingo", + "ovoblanko", + "ovri", + "ovulado", + "ozono", + "pacama", + "padeli", + "pafilo", + "pagigi", + "pajlo", + "paketo", + "palaco", + "pampelmo", + "pantalono", + "papero", + "paroli", + "pasejo", + "patro", + "pavimo", + "peco", + "pedalo", + "peklita", + "pelikano", + "pensiono", + "peplomo", + "pesilo", + "petanto", + "pezoforto", + "piano", + "picejo", + "piede", + "pigmento", + "pikema", + "pilkoludo", + "pimento", + "pinglo", + "pioniro", + "pipromento", + "pirato", + "pistolo", + "pitoreska", + "piulo", + "pivoti", + "pizango", + "planko", + "plektita", + "plibonigi", + "ploradi", + "plurlingva", + "pobo", + "podio", + "poeto", + "pogranda", + "pohora", + "pokalo", + "politekniko", + "pomarbo", + "ponevosto", + "populara", + "porcelana", + "postkompreno", + "poteto", + "poviga", + "pozitiva", + "prapatroj", + "precize", + "pridemandi", + "probable", + "pruntanto", + "psalmo", + "psikologio", + "psoriazo", + "pterido", + "publiko", + "pudro", + "pufo", + "pugnobato", + "pulovero", + "pumpi", + "punkto", + "pupo", + "pureo", + "puso", + "putrema", + "puzlo", + "rabate", + "racionala", + "radiko", + "rafinado", + "raguo", + "rajto", + "rakonti", + "ralio", + "rampi", + "rando", + "rapida", + "rastruma", + "ratifiki", + "raviolo", + "razeno", + "reakcio", + "rebildo", + "recepto", + "redakti", + "reenigi", + "reformi", + "regiono", + "rehavi", + "reinspekti", + "rejesi", + "reklamo", + "relativa", + "rememori", + "renkonti", + "reorganizado", + "reprezenti", + "respondi", + "retumilo", + "reuzebla", + "revidi", + "rezulti", + "rialo", + "ribeli", + "ricevi", + "ridiga", + "rifuginto", + "rigardi", + "rikolti", + "rilati", + "rimarki", + "rinocero", + "ripozi", + "riski", + "ritmo", + "rivero", + "rizokampo", + "roboto", + "rododendro", + "rojo", + "rokmuziko", + "rolvorto", + "romantika", + "ronroni", + "rosino", + "rotondo", + "rovero", + "rozeto", + "rubando", + "rudimenta", + "rufa", + "rugbeo", + "ruino", + "ruleto", + "rumoro", + "runo", + "rupio", + "rura", + "rustimuna", + "ruzulo", + "sabato", + "sadismo", + "safario", + "sagaca", + "sakfluto", + "salti", + "samtage", + "sandalo", + "sapejo", + "sarongo", + "satelito", + "savano", + "sbiro", + "sciado", + "seanco", + "sebo", + "sedativo", + "segligno", + "sekretario", + "selektiva", + "semajno", + "senpeza", + "separeo", + "servilo", + "sesangulo", + "setli", + "seurigi", + "severa", + "sezono", + "sfagno", + "sfero", + "sfinkso", + "siatempe", + "siblado", + "sidejo", + "siesto", + "sifono", + "signalo", + "siklo", + "silenti", + "simpla", + "sinjoro", + "siropo", + "sistemo", + "situacio", + "siverto", + "sizifa", + "skatolo", + "skemo", + "skianto", + "sklavo", + "skorpio", + "skribisto", + "skulpti", + "skvamo", + "slango", + "sledeto", + "sliparo", + "smeraldo", + "smirgi", + "smokingo", + "smuto", + "snoba", + "snufegi", + "sobra", + "sociano", + "sodakvo", + "sofo", + "soifi", + "sojlo", + "soklo", + "soldato", + "somero", + "sonilo", + "sopiri", + "sorto", + "soulo", + "soveto", + "sparkado", + "speciala", + "spiri", + "splito", + "sporto", + "sprita", + "spuro", + "stabila", + "stelfiguro", + "stimulo", + "stomako", + "strato", + "studanto", + "subgrupo", + "suden", + "suferanta", + "sugesti", + "suito", + "sukero", + "sulko", + "sume", + "sunlumo", + "super", + "surskribeto", + "suspekti", + "suturo", + "svati", + "svenfali", + "svingi", + "svopo", + "tabako", + "taglumo", + "tajloro", + "taksimetro", + "talento", + "tamen", + "tanko", + "taoismo", + "tapioko", + "tarifo", + "tasko", + "tatui", + "taverno", + "teatro", + "tedlaboro", + "tegmento", + "tehoro", + "teknika", + "telefono", + "tempo", + "tenisejo", + "teorie", + "teraso", + "testudo", + "tetablo", + "teujo", + "tezo", + "tialo", + "tibio", + "tielnomata", + "tifono", + "tigro", + "tikli", + "timida", + "tinkturo", + "tiom", + "tiparo", + "tirkesto", + "titolo", + "tiutempe", + "tizano", + "tobogano", + "tofeo", + "togo", + "toksa", + "tolerema", + "tombolo", + "tondri", + "topografio", + "tordeti", + "tosti", + "totalo", + "traduko", + "tredi", + "triangulo", + "tropika", + "trumpeto", + "tualeto", + "tubisto", + "tufgrebo", + "tuja", + "tukano", + "tulipo", + "tumulto", + "tunelo", + "turisto", + "tusi", + "tutmonda", + "tvisto", + "udono", + "uesto", + "ukazo", + "ukelelo", + "ulcero", + "ulmo", + "ultimato", + "ululi", + "umbiliko", + "unco", + "ungego", + "uniformo", + "unkti", + "unukolora", + "uragano", + "urbano", + "uretro", + "urino", + "ursido", + "uskleco", + "usonigi", + "utero", + "utila", + "utopia", + "uverturo", + "uzadi", + "uzeblo", + "uzino", + "uzkutimo", + "uzofini", + "uzurpi", + "uzvaloro", + "vadejo", + "vafleto", + "vagono", + "vahabismo", + "vajco", + "vakcino", + "valoro", + "vampiro", + "vangharoj", + "vaporo", + "varma", + "vasta", + "vato", + "vazaro", + "veaspekta", + "vedismo", + "vegetalo", + "vehiklo", + "vejno", + "vekita", + "velstango", + "vemieno", + "vendi", + "vepro", + "verando", + "vespero", + "veturi", + "veziko", + "viando", + "vibri", + "vico", + "videbla", + "vifio", + "vigla", + "viktimo", + "vila", + "vimeno", + "vintro", + "violo", + "vippuno", + "virtuala", + "viskoza", + "vitro", + "viveca", + "viziti", + "vobli", + "vodko", + "vojeto", + "vokegi", + "volbo", + "vomema", + "vono", + "vortaro", + "vosto", + "voti", + "vrako", + "vringi", + "vualo", + "vulkano", + "vundo", + "vuvuzelo", + "zamenhofa", + "zapi", + "zebro", + "zefiro", + "zeloto", + "zenismo", + "zeolito", + "zepelino", + "zeto", + "zigzagi", + "zinko", + "zipo", + "zirkonio", + "zodiako", + "zoeto", + "zombio", + "zono", + "zoologio", + "zorgi", + "zukino", + "zumilo" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/es.json b/coins/monero/src/wallet/seed/classic/es.json new file mode 100644 index 00000000..997df613 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/es.json @@ -0,0 +1,1628 @@ +[ + "ábaco", + "abdomen", + "abeja", + "abierto", + "abogado", + "abono", + "aborto", + "abrazo", + "abrir", + "abuelo", + "abuso", + "acabar", + "academia", + "acceso", + "acción", + "aceite", + "acelga", + "acento", + "aceptar", + "ácido", + "aclarar", + "acné", + "acoger", + "acoso", + "activo", + "acto", + "actriz", + "actuar", + "acudir", + "acuerdo", + "acusar", + "adicto", + "admitir", + "adoptar", + "adorno", + "aduana", + "adulto", + "aéreo", + "afectar", + "afición", + "afinar", + "afirmar", + "ágil", + "agitar", + "agonía", + "agosto", + "agotar", + "agregar", + "agrio", + "agua", + "agudo", + "águila", + "aguja", + "ahogo", + "ahorro", + "aire", + "aislar", + "ajedrez", + "ajeno", + "ajuste", + "alacrán", + "alambre", + "alarma", + "alba", + "álbum", + "alcalde", + "aldea", + "alegre", + "alejar", + "alerta", + "aleta", + "alfiler", + "alga", + "algodón", + "aliado", + "aliento", + "alivio", + "alma", + "almeja", + "almíbar", + "altar", + "alteza", + "altivo", + "alto", + "altura", + "alumno", + "alzar", + "amable", + "amante", + "amapola", + "amargo", + "amasar", + "ámbar", + "ámbito", + "ameno", + "amigo", + "amistad", + "amor", + "amparo", + "amplio", + "ancho", + "anciano", + "ancla", + "andar", + "andén", + "anemia", + "ángulo", + "anillo", + "ánimo", + "anís", + "anotar", + "antena", + "antiguo", + "antojo", + "anual", + "anular", + "anuncio", + "añadir", + "añejo", + "año", + "apagar", + "aparato", + "apetito", + "apio", + "aplicar", + "apodo", + "aporte", + "apoyo", + "aprender", + "aprobar", + "apuesta", + "apuro", + "arado", + "araña", + "arar", + "árbitro", + "árbol", + "arbusto", + "archivo", + "arco", + "arder", + "ardilla", + "arduo", + "área", + "árido", + "aries", + "armonía", + "arnés", + "aroma", + "arpa", + "arpón", + "arreglo", + "arroz", + "arruga", + "arte", + "artista", + "asa", + "asado", + "asalto", + "ascenso", + "asegurar", + "aseo", + "asesor", + "asiento", + "asilo", + "asistir", + "asno", + "asombro", + "áspero", + "astilla", + "astro", + "astuto", + "asumir", + "asunto", + "atajo", + "ataque", + "atar", + "atento", + "ateo", + "ático", + "atleta", + "átomo", + "atraer", + "atroz", + "atún", + "audaz", + "audio", + "auge", + "aula", + "aumento", + "ausente", + "autor", + "aval", + "avance", + "avaro", + "ave", + "avellana", + "avena", + "avestruz", + "avión", + "aviso", + "ayer", + "ayuda", + "ayuno", + "azafrán", + "azar", + "azote", + "azúcar", + "azufre", + "azul", + "baba", + "babor", + "bache", + "bahía", + "baile", + "bajar", + "balanza", + "balcón", + "balde", + "bambú", + "banco", + "banda", + "baño", + "barba", + "barco", + "barniz", + "barro", + "báscula", + "bastón", + "basura", + "batalla", + "batería", + "batir", + "batuta", + "baúl", + "bazar", + "bebé", + "bebida", + "bello", + "besar", + "beso", + "bestia", + "bicho", + "bien", + "bingo", + "blanco", + "bloque", + "blusa", + "boa", + "bobina", + "bobo", + "boca", + "bocina", + "boda", + "bodega", + "boina", + "bola", + "bolero", + "bolsa", + "bomba", + "bondad", + "bonito", + "bono", + "bonsái", + "borde", + "borrar", + "bosque", + "bote", + "botín", + "bóveda", + "bozal", + "bravo", + "brazo", + "brecha", + "breve", + "brillo", + "brinco", + "brisa", + "broca", + "broma", + "bronce", + "brote", + "bruja", + "brusco", + "bruto", + "buceo", + "bucle", + "bueno", + "buey", + "bufanda", + "bufón", + "búho", + "buitre", + "bulto", + "burbuja", + "burla", + "burro", + "buscar", + "butaca", + "buzón", + "caballo", + "cabeza", + "cabina", + "cabra", + "cacao", + "cadáver", + "cadena", + "caer", + "café", + "caída", + "caimán", + "caja", + "cajón", + "cal", + "calamar", + "calcio", + "caldo", + "calidad", + "calle", + "calma", + "calor", + "calvo", + "cama", + "cambio", + "camello", + "camino", + "campo", + "cáncer", + "candil", + "canela", + "canguro", + "canica", + "canto", + "caña", + "cañón", + "caoba", + "caos", + "capaz", + "capitán", + "capote", + "captar", + "capucha", + "cara", + "carbón", + "cárcel", + "careta", + "carga", + "cariño", + "carne", + "carpeta", + "carro", + "carta", + "casa", + "casco", + "casero", + "caspa", + "castor", + "catorce", + "catre", + "caudal", + "causa", + "cazo", + "cebolla", + "ceder", + "cedro", + "celda", + "célebre", + "celoso", + "célula", + "cemento", + "ceniza", + "centro", + "cerca", + "cerdo", + "cereza", + "cero", + "cerrar", + "certeza", + "césped", + "cetro", + "chacal", + "chaleco", + "champú", + "chancla", + "chapa", + "charla", + "chico", + "chiste", + "chivo", + "choque", + "choza", + "chuleta", + "chupar", + "ciclón", + "ciego", + "cielo", + "cien", + "cierto", + "cifra", + "cigarro", + "cima", + "cinco", + "cine", + "cinta", + "ciprés", + "circo", + "ciruela", + "cisne", + "cita", + "ciudad", + "clamor", + "clan", + "claro", + "clase", + "clave", + "cliente", + "clima", + "clínica", + "cobre", + "cocción", + "cochino", + "cocina", + "coco", + "código", + "codo", + "cofre", + "coger", + "cohete", + "cojín", + "cojo", + "cola", + "colcha", + "colegio", + "colgar", + "colina", + "collar", + "colmo", + "columna", + "combate", + "comer", + "comida", + "cómodo", + "compra", + "conde", + "conejo", + "conga", + "conocer", + "consejo", + "contar", + "copa", + "copia", + "corazón", + "corbata", + "corcho", + "cordón", + "corona", + "correr", + "coser", + "cosmos", + "costa", + "cráneo", + "cráter", + "crear", + "crecer", + "creído", + "crema", + "cría", + "crimen", + "cripta", + "crisis", + "cromo", + "crónica", + "croqueta", + "crudo", + "cruz", + "cuadro", + "cuarto", + "cuatro", + "cubo", + "cubrir", + "cuchara", + "cuello", + "cuento", + "cuerda", + "cuesta", + "cueva", + "cuidar", + "culebra", + "culpa", + "culto", + "cumbre", + "cumplir", + "cuna", + "cuneta", + "cuota", + "cupón", + "cúpula", + "curar", + "curioso", + "curso", + "curva", + "cutis", + "dama", + "danza", + "dar", + "dardo", + "dátil", + "deber", + "débil", + "década", + "decir", + "dedo", + "defensa", + "definir", + "dejar", + "delfín", + "delgado", + "delito", + "demora", + "denso", + "dental", + "deporte", + "derecho", + "derrota", + "desayuno", + "deseo", + "desfile", + "desnudo", + "destino", + "desvío", + "detalle", + "detener", + "deuda", + "día", + "diablo", + "diadema", + "diamante", + "diana", + "diario", + "dibujo", + "dictar", + "diente", + "dieta", + "diez", + "difícil", + "digno", + "dilema", + "diluir", + "dinero", + "directo", + "dirigir", + "disco", + "diseño", + "disfraz", + "diva", + "divino", + "doble", + "doce", + "dolor", + "domingo", + "don", + "donar", + "dorado", + "dormir", + "dorso", + "dos", + "dosis", + "dragón", + "droga", + "ducha", + "duda", + "duelo", + "dueño", + "dulce", + "dúo", + "duque", + "durar", + "dureza", + "duro", + "ébano", + "ebrio", + "echar", + "eco", + "ecuador", + "edad", + "edición", + "edificio", + "editor", + "educar", + "efecto", + "eficaz", + "eje", + "ejemplo", + "elefante", + "elegir", + "elemento", + "elevar", + "elipse", + "élite", + "elixir", + "elogio", + "eludir", + "embudo", + "emitir", + "emoción", + "empate", + "empeño", + "empleo", + "empresa", + "enano", + "encargo", + "enchufe", + "encía", + "enemigo", + "enero", + "enfado", + "enfermo", + "engaño", + "enigma", + "enlace", + "enorme", + "enredo", + "ensayo", + "enseñar", + "entero", + "entrar", + "envase", + "envío", + "época", + "equipo", + "erizo", + "escala", + "escena", + "escolar", + "escribir", + "escudo", + "esencia", + "esfera", + "esfuerzo", + "espada", + "espejo", + "espía", + "esposa", + "espuma", + "esquí", + "estar", + "este", + "estilo", + "estufa", + "etapa", + "eterno", + "ética", + "etnia", + "evadir", + "evaluar", + "evento", + "evitar", + "exacto", + "examen", + "exceso", + "excusa", + "exento", + "exigir", + "exilio", + "existir", + "éxito", + "experto", + "explicar", + "exponer", + "extremo", + "fábrica", + "fábula", + "fachada", + "fácil", + "factor", + "faena", + "faja", + "falda", + "fallo", + "falso", + "faltar", + "fama", + "familia", + "famoso", + "faraón", + "farmacia", + "farol", + "farsa", + "fase", + "fatiga", + "fauna", + "favor", + "fax", + "febrero", + "fecha", + "feliz", + "feo", + "feria", + "feroz", + "fértil", + "fervor", + "festín", + "fiable", + "fianza", + "fiar", + "fibra", + "ficción", + "ficha", + "fideo", + "fiebre", + "fiel", + "fiera", + "fiesta", + "figura", + "fijar", + "fijo", + "fila", + "filete", + "filial", + "filtro", + "fin", + "finca", + "fingir", + "finito", + "firma", + "flaco", + "flauta", + "flecha", + "flor", + "flota", + "fluir", + "flujo", + "flúor", + "fobia", + "foca", + "fogata", + "fogón", + "folio", + "folleto", + "fondo", + "forma", + "forro", + "fortuna", + "forzar", + "fosa", + "foto", + "fracaso", + "frágil", + "franja", + "frase", + "fraude", + "freír", + "freno", + "fresa", + "frío", + "frito", + "fruta", + "fuego", + "fuente", + "fuerza", + "fuga", + "fumar", + "función", + "funda", + "furgón", + "furia", + "fusil", + "fútbol", + "futuro", + "gacela", + "gafas", + "gaita", + "gajo", + "gala", + "galería", + "gallo", + "gamba", + "ganar", + "gancho", + "ganga", + "ganso", + "garaje", + "garza", + "gasolina", + "gastar", + "gato", + "gavilán", + "gemelo", + "gemir", + "gen", + "género", + "genio", + "gente", + "geranio", + "gerente", + "germen", + "gesto", + "gigante", + "gimnasio", + "girar", + "giro", + "glaciar", + "globo", + "gloria", + "gol", + "golfo", + "goloso", + "golpe", + "goma", + "gordo", + "gorila", + "gorra", + "gota", + "goteo", + "gozar", + "grada", + "gráfico", + "grano", + "grasa", + "gratis", + "grave", + "grieta", + "grillo", + "gripe", + "gris", + "grito", + "grosor", + "grúa", + "grueso", + "grumo", + "grupo", + "guante", + "guapo", + "guardia", + "guerra", + "guía", + "guiño", + "guion", + "guiso", + "guitarra", + "gusano", + "gustar", + "haber", + "hábil", + "hablar", + "hacer", + "hacha", + "hada", + "hallar", + "hamaca", + "harina", + "haz", + "hazaña", + "hebilla", + "hebra", + "hecho", + "helado", + "helio", + "hembra", + "herir", + "hermano", + "héroe", + "hervir", + "hielo", + "hierro", + "hígado", + "higiene", + "hijo", + "himno", + "historia", + "hocico", + "hogar", + "hoguera", + "hoja", + "hombre", + "hongo", + "honor", + "honra", + "hora", + "hormiga", + "horno", + "hostil", + "hoyo", + "hueco", + "huelga", + "huerta", + "hueso", + "huevo", + "huida", + "huir", + "humano", + "húmedo", + "humilde", + "humo", + "hundir", + "huracán", + "hurto", + "icono", + "ideal", + "idioma", + "ídolo", + "iglesia", + "iglú", + "igual", + "ilegal", + "ilusión", + "imagen", + "imán", + "imitar", + "impar", + "imperio", + "imponer", + "impulso", + "incapaz", + "índice", + "inerte", + "infiel", + "informe", + "ingenio", + "inicio", + "inmenso", + "inmune", + "innato", + "insecto", + "instante", + "interés", + "íntimo", + "intuir", + "inútil", + "invierno", + "ira", + "iris", + "ironía", + "isla", + "islote", + "jabalí", + "jabón", + "jamón", + "jarabe", + "jardín", + "jarra", + "jaula", + "jazmín", + "jefe", + "jeringa", + "jinete", + "jornada", + "joroba", + "joven", + "joya", + "juerga", + "jueves", + "juez", + "jugador", + "jugo", + "juguete", + "juicio", + "junco", + "jungla", + "junio", + "juntar", + "júpiter", + "jurar", + "justo", + "juvenil", + "juzgar", + "kilo", + "koala", + "labio", + "lacio", + "lacra", + "lado", + "ladrón", + "lagarto", + "lágrima", + "laguna", + "laico", + "lamer", + "lámina", + "lámpara", + "lana", + "lancha", + "langosta", + "lanza", + "lápiz", + "largo", + "larva", + "lástima", + "lata", + "látex", + "latir", + "laurel", + "lavar", + "lazo", + "leal", + "lección", + "leche", + "lector", + "leer", + "legión", + "legumbre", + "lejano", + "lengua", + "lento", + "leña", + "león", + "leopardo", + "lesión", + "letal", + "letra", + "leve", + "leyenda", + "libertad", + "libro", + "licor", + "líder", + "lidiar", + "lienzo", + "liga", + "ligero", + "lima", + "límite", + "limón", + "limpio", + "lince", + "lindo", + "línea", + "lingote", + "lino", + "linterna", + "líquido", + "liso", + "lista", + "litera", + "litio", + "litro", + "llaga", + "llama", + "llanto", + "llave", + "llegar", + "llenar", + "llevar", + "llorar", + "llover", + "lluvia", + "lobo", + "loción", + "loco", + "locura", + "lógica", + "logro", + "lombriz", + "lomo", + "lonja", + "lote", + "lucha", + "lucir", + "lugar", + "lujo", + "luna", + "lunes", + "lupa", + "lustro", + "luto", + "luz", + "maceta", + "macho", + "madera", + "madre", + "maduro", + "maestro", + "mafia", + "magia", + "mago", + "maíz", + "maldad", + "maleta", + "malla", + "malo", + "mamá", + "mambo", + "mamut", + "manco", + "mando", + "manejar", + "manga", + "maniquí", + "manjar", + "mano", + "manso", + "manta", + "mañana", + "mapa", + "máquina", + "mar", + "marco", + "marea", + "marfil", + "margen", + "marido", + "mármol", + "marrón", + "martes", + "marzo", + "masa", + "máscara", + "masivo", + "matar", + "materia", + "matiz", + "matriz", + "máximo", + "mayor", + "mazorca", + "mecha", + "medalla", + "medio", + "médula", + "mejilla", + "mejor", + "melena", + "melón", + "memoria", + "menor", + "mensaje", + "mente", + "menú", + "mercado", + "merengue", + "mérito", + "mes", + "mesón", + "meta", + "meter", + "método", + "metro", + "mezcla", + "miedo", + "miel", + "miembro", + "miga", + "mil", + "milagro", + "militar", + "millón", + "mimo", + "mina", + "minero", + "mínimo", + "minuto", + "miope", + "mirar", + "misa", + "miseria", + "misil", + "mismo", + "mitad", + "mito", + "mochila", + "moción", + "moda", + "modelo", + "moho", + "mojar", + "molde", + "moler", + "molino", + "momento", + "momia", + "monarca", + "moneda", + "monja", + "monto", + "moño", + "morada", + "morder", + "moreno", + "morir", + "morro", + "morsa", + "mortal", + "mosca", + "mostrar", + "motivo", + "mover", + "móvil", + "mozo", + "mucho", + "mudar", + "mueble", + "muela", + "muerte", + "muestra", + "mugre", + "mujer", + "mula", + "muleta", + "multa", + "mundo", + "muñeca", + "mural", + "muro", + "músculo", + "museo", + "musgo", + "música", + "muslo", + "nácar", + "nación", + "nadar", + "naipe", + "naranja", + "nariz", + "narrar", + "nasal", + "natal", + "nativo", + "natural", + "náusea", + "naval", + "nave", + "navidad", + "necio", + "néctar", + "negar", + "negocio", + "negro", + "neón", + "nervio", + "neto", + "neutro", + "nevar", + "nevera", + "nicho", + "nido", + "niebla", + "nieto", + "niñez", + "niño", + "nítido", + "nivel", + "nobleza", + "noche", + "nómina", + "noria", + "norma", + "norte", + "nota", + "noticia", + "novato", + "novela", + "novio", + "nube", + "nuca", + "núcleo", + "nudillo", + "nudo", + "nuera", + "nueve", + "nuez", + "nulo", + "número", + "nutria", + "oasis", + "obeso", + "obispo", + "objeto", + "obra", + "obrero", + "observar", + "obtener", + "obvio", + "oca", + "ocaso", + "océano", + "ochenta", + "ocho", + "ocio", + "ocre", + "octavo", + "octubre", + "oculto", + "ocupar", + "ocurrir", + "odiar", + "odio", + "odisea", + "oeste", + "ofensa", + "oferta", + "oficio", + "ofrecer", + "ogro", + "oído", + "oír", + "ojo", + "ola", + "oleada", + "olfato", + "olivo", + "olla", + "olmo", + "olor", + "olvido", + "ombligo", + "onda", + "onza", + "opaco", + "opción", + "ópera", + "opinar", + "oponer", + "optar", + "óptica", + "opuesto", + "oración", + "orador", + "oral", + "órbita", + "orca", + "orden", + "oreja", + "órgano", + "orgía", + "orgullo", + "oriente", + "origen", + "orilla", + "oro", + "orquesta", + "oruga", + "osadía", + "oscuro", + "osezno", + "oso", + "ostra", + "otoño", + "otro", + "oveja", + "óvulo", + "óxido", + "oxígeno", + "oyente", + "ozono", + "pacto", + "padre", + "paella", + "página", + "pago", + "país", + "pájaro", + "palabra", + "palco", + "paleta", + "pálido", + "palma", + "paloma", + "palpar", + "pan", + "panal", + "pánico", + "pantera", + "pañuelo", + "papá", + "papel", + "papilla", + "paquete", + "parar", + "parcela", + "pared", + "parir", + "paro", + "párpado", + "parque", + "párrafo", + "parte", + "pasar", + "paseo", + "pasión", + "paso", + "pasta", + "pata", + "patio", + "patria", + "pausa", + "pauta", + "pavo", + "payaso", + "peatón", + "pecado", + "pecera", + "pecho", + "pedal", + "pedir", + "pegar", + "peine", + "pelar", + "peldaño", + "pelea", + "peligro", + "pellejo", + "pelo", + "peluca", + "pena", + "pensar", + "peñón", + "peón", + "peor", + "pepino", + "pequeño", + "pera", + "percha", + "perder", + "pereza", + "perfil", + "perico", + "perla", + "permiso", + "perro", + "persona", + "pesa", + "pesca", + "pésimo", + "pestaña", + "pétalo", + "petróleo", + "pez", + "pezuña", + "picar", + "pichón", + "pie", + "piedra", + "pierna", + "pieza", + "pijama", + "pilar", + "piloto", + "pimienta", + "pino", + "pintor", + "pinza", + "piña", + "piojo", + "pipa", + "pirata", + "pisar", + "piscina", + "piso", + "pista", + "pitón", + "pizca", + "placa", + "plan", + "plata", + "playa", + "plaza", + "pleito", + "pleno", + "plomo", + "pluma", + "plural", + "pobre", + "poco", + "poder", + "podio", + "poema", + "poesía", + "poeta", + "polen", + "policía", + "pollo", + "polvo", + "pomada", + "pomelo", + "pomo", + "pompa", + "poner", + "porción", + "portal", + "posada", + "poseer", + "posible", + "poste", + "potencia", + "potro", + "pozo", + "prado", + "precoz", + "pregunta", + "premio", + "prensa", + "preso", + "previo", + "primo", + "príncipe", + "prisión", + "privar", + "proa", + "probar", + "proceso", + "producto", + "proeza", + "profesor", + "programa", + "prole", + "promesa", + "pronto", + "propio", + "próximo", + "prueba", + "público", + "puchero", + "pudor", + "pueblo", + "puerta", + "puesto", + "pulga", + "pulir", + "pulmón", + "pulpo", + "pulso", + "puma", + "punto", + "puñal", + "puño", + "pupa", + "pupila", + "puré", + "quedar", + "queja", + "quemar", + "querer", + "queso", + "quieto", + "química", + "quince", + "quitar", + "rábano", + "rabia", + "rabo", + "ración", + "radical", + "raíz", + "rama", + "rampa", + "rancho", + "rango", + "rapaz", + "rápido", + "rapto", + "rasgo", + "raspa", + "rato", + "rayo", + "raza", + "razón", + "reacción", + "realidad", + "rebaño", + "rebote", + "recaer", + "receta", + "rechazo", + "recoger", + "recreo", + "recto", + "recurso", + "red", + "redondo", + "reducir", + "reflejo", + "reforma", + "refrán", + "refugio", + "regalo", + "regir", + "regla", + "regreso", + "rehén", + "reino", + "reír", + "reja", + "relato", + "relevo", + "relieve", + "relleno", + "reloj", + "remar", + "remedio", + "remo", + "rencor", + "rendir", + "renta", + "reparto", + "repetir", + "reposo", + "reptil", + "res", + "rescate", + "resina", + "respeto", + "resto", + "resumen", + "retiro", + "retorno", + "retrato", + "reunir", + "revés", + "revista", + "rey", + "rezar", + "rico", + "riego", + "rienda", + "riesgo", + "rifa", + "rígido", + "rigor", + "rincón", + "riñón", + "río", + "riqueza", + "risa", + "ritmo", + "rito" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/fr.json b/coins/monero/src/wallet/seed/classic/fr.json new file mode 100644 index 00000000..65663afc --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/fr.json @@ -0,0 +1,1628 @@ +[ + "abandon", + "abattre", + "aboi", + "abolir", + "aborder", + "abri", + "absence", + "absolu", + "abuser", + "acacia", + "acajou", + "accent", + "accord", + "accrocher", + "accuser", + "acerbe", + "achat", + "acheter", + "acide", + "acier", + "acquis", + "acte", + "action", + "adage", + "adepte", + "adieu", + "admettre", + "admis", + "adorer", + "adresser", + "aduler", + "affaire", + "affirmer", + "afin", + "agacer", + "agent", + "agir", + "agiter", + "agonie", + "agrafe", + "agrume", + "aider", + "aigle", + "aigre", + "aile", + "ailleurs", + "aimant", + "aimer", + "ainsi", + "aise", + "ajouter", + "alarme", + "album", + "alcool", + "alerte", + "algue", + "alibi", + "aller", + "allumer", + "alors", + "amande", + "amener", + "amie", + "amorcer", + "amour", + "ample", + "amuser", + "ananas", + "ancien", + "anglais", + "angoisse", + "animal", + "anneau", + "annoncer", + "apercevoir", + "apparence", + "appel", + "apporter", + "apprendre", + "appuyer", + "arbre", + "arcade", + "arceau", + "arche", + "ardeur", + "argent", + "argile", + "aride", + "arme", + "armure", + "arracher", + "arriver", + "article", + "asile", + "aspect", + "assaut", + "assez", + "assister", + "assurer", + "astre", + "astuce", + "atlas", + "atroce", + "attacher", + "attente", + "attirer", + "aube", + "aucun", + "audace", + "auparavant", + "auquel", + "aurore", + "aussi", + "autant", + "auteur", + "autoroute", + "autre", + "aval", + "avant", + "avec", + "avenir", + "averse", + "aveu", + "avide", + "avion", + "avis", + "avoir", + "avouer", + "avril", + "azote", + "azur", + "badge", + "bagage", + "bague", + "bain", + "baisser", + "balai", + "balcon", + "balise", + "balle", + "bambou", + "banane", + "banc", + "bandage", + "banjo", + "banlieue", + "bannir", + "banque", + "baobab", + "barbe", + "barque", + "barrer", + "bassine", + "bataille", + "bateau", + "battre", + "baver", + "bavoir", + "bazar", + "beau", + "beige", + "berger", + "besoin", + "beurre", + "biais", + "biceps", + "bidule", + "bien", + "bijou", + "bilan", + "billet", + "blanc", + "blason", + "bleu", + "bloc", + "blond", + "bocal", + "boire", + "boiserie", + "boiter", + "bonbon", + "bondir", + "bonheur", + "bordure", + "borgne", + "borner", + "bosse", + "bouche", + "bouder", + "bouger", + "boule", + "bourse", + "bout", + "boxe", + "brader", + "braise", + "branche", + "braquer", + "bras", + "brave", + "brebis", + "brevet", + "brider", + "briller", + "brin", + "brique", + "briser", + "broche", + "broder", + "bronze", + "brosser", + "brouter", + "bruit", + "brute", + "budget", + "buffet", + "bulle", + "bureau", + "buriner", + "buste", + "buter", + "butiner", + "cabas", + "cabinet", + "cabri", + "cacao", + "cacher", + "cadeau", + "cadre", + "cage", + "caisse", + "caler", + "calme", + "camarade", + "camion", + "campagne", + "canal", + "canif", + "capable", + "capot", + "carat", + "caresser", + "carie", + "carpe", + "cartel", + "casier", + "casque", + "casserole", + "cause", + "cavale", + "cave", + "ceci", + "cela", + "celui", + "cendre", + "cent", + "cependant", + "cercle", + "cerise", + "cerner", + "certes", + "cerveau", + "cesser", + "chacun", + "chair", + "chaleur", + "chamois", + "chanson", + "chaque", + "charge", + "chasse", + "chat", + "chaud", + "chef", + "chemin", + "cheveu", + "chez", + "chicane", + "chien", + "chiffre", + "chiner", + "chiot", + "chlore", + "choc", + "choix", + "chose", + "chou", + "chute", + "cibler", + "cidre", + "ciel", + "cigale", + "cinq", + "cintre", + "cirage", + "cirque", + "ciseau", + "citation", + "citer", + "citron", + "civet", + "clairon", + "clan", + "classe", + "clavier", + "clef", + "climat", + "cloche", + "cloner", + "clore", + "clos", + "clou", + "club", + "cobra", + "cocon", + "coiffer", + "coin", + "colline", + "colon", + "combat", + "comme", + "compte", + "conclure", + "conduire", + "confier", + "connu", + "conseil", + "contre", + "convenir", + "copier", + "cordial", + "cornet", + "corps", + "cosmos", + "coton", + "couche", + "coude", + "couler", + "coupure", + "cour", + "couteau", + "couvrir", + "crabe", + "crainte", + "crampe", + "cran", + "creuser", + "crever", + "crier", + "crime", + "crin", + "crise", + "crochet", + "croix", + "cruel", + "cuisine", + "cuite", + "culot", + "culte", + "cumul", + "cure", + "curieux", + "cuve", + "dame", + "danger", + "dans", + "davantage", + "debout", + "dedans", + "dehors", + "delta", + "demain", + "demeurer", + "demi", + "dense", + "dent", + "depuis", + "dernier", + "descendre", + "dessus", + "destin", + "dette", + "deuil", + "deux", + "devant", + "devenir", + "devin", + "devoir", + "dicton", + "dieu", + "difficile", + "digestion", + "digue", + "diluer", + "dimanche", + "dinde", + "diode", + "dire", + "diriger", + "discours", + "disposer", + "distance", + "divan", + "divers", + "docile", + "docteur", + "dodu", + "dogme", + "doigt", + "dominer", + "donation", + "donjon", + "donner", + "dopage", + "dorer", + "dormir", + "doseur", + "douane", + "double", + "douche", + "douleur", + "doute", + "doux", + "douzaine", + "draguer", + "drame", + "drap", + "dresser", + "droit", + "duel", + "dune", + "duper", + "durant", + "durcir", + "durer", + "eaux", + "effacer", + "effet", + "effort", + "effrayant", + "elle", + "embrasser", + "emmener", + "emparer", + "empire", + "employer", + "emporter", + "enclos", + "encore", + "endive", + "endormir", + "endroit", + "enduit", + "enfant", + "enfermer", + "enfin", + "enfler", + "enfoncer", + "enfuir", + "engager", + "engin", + "enjeu", + "enlever", + "ennemi", + "ennui", + "ensemble", + "ensuite", + "entamer", + "entendre", + "entier", + "entourer", + "entre", + "envelopper", + "envie", + "envoyer", + "erreur", + "escalier", + "espace", + "espoir", + "esprit", + "essai", + "essor", + "essuyer", + "estimer", + "exact", + "examiner", + "excuse", + "exemple", + "exiger", + "exil", + "exister", + "exode", + "expliquer", + "exposer", + "exprimer", + "extase", + "fable", + "facette", + "facile", + "fade", + "faible", + "faim", + "faire", + "fait", + "falloir", + "famille", + "faner", + "farce", + "farine", + "fatigue", + "faucon", + "faune", + "faute", + "faux", + "faveur", + "favori", + "faxer", + "feinter", + "femme", + "fendre", + "fente", + "ferme", + "festin", + "feuille", + "feutre", + "fiable", + "fibre", + "ficher", + "fier", + "figer", + "figure", + "filet", + "fille", + "filmer", + "fils", + "filtre", + "final", + "finesse", + "finir", + "fiole", + "firme", + "fixe", + "flacon", + "flair", + "flamme", + "flan", + "flaque", + "fleur", + "flocon", + "flore", + "flot", + "flou", + "fluide", + "fluor", + "flux", + "focus", + "foin", + "foire", + "foison", + "folie", + "fonction", + "fondre", + "fonte", + "force", + "forer", + "forger", + "forme", + "fort", + "fosse", + "fouet", + "fouine", + "foule", + "four", + "foyer", + "frais", + "franc", + "frapper", + "freiner", + "frimer", + "friser", + "frite", + "froid", + "froncer", + "fruit", + "fugue", + "fuir", + "fuite", + "fumer", + "fureur", + "furieux", + "fuser", + "fusil", + "futile", + "futur", + "gagner", + "gain", + "gala", + "galet", + "galop", + "gamme", + "gant", + "garage", + "garde", + "garer", + "gauche", + "gaufre", + "gaule", + "gaver", + "gazon", + "geler", + "genou", + "genre", + "gens", + "gercer", + "germer", + "geste", + "gibier", + "gicler", + "gilet", + "girafe", + "givre", + "glace", + "glisser", + "globe", + "gloire", + "gluant", + "gober", + "golf", + "gommer", + "gorge", + "gosier", + "goutte", + "grain", + "gramme", + "grand", + "gras", + "grave", + "gredin", + "griffure", + "griller", + "gris", + "gronder", + "gros", + "grotte", + "groupe", + "grue", + "guerrier", + "guetter", + "guider", + "guise", + "habiter", + "hache", + "haie", + "haine", + "halte", + "hamac", + "hanche", + "hangar", + "hanter", + "haras", + "hareng", + "harpe", + "hasard", + "hausse", + "haut", + "havre", + "herbe", + "heure", + "hibou", + "hier", + "histoire", + "hiver", + "hochet", + "homme", + "honneur", + "honte", + "horde", + "horizon", + "hormone", + "houle", + "housse", + "hublot", + "huile", + "huit", + "humain", + "humble", + "humide", + "humour", + "hurler", + "idole", + "igloo", + "ignorer", + "illusion", + "image", + "immense", + "immobile", + "imposer", + "impression", + "incapable", + "inconnu", + "index", + "indiquer", + "infime", + "injure", + "inox", + "inspirer", + "instant", + "intention", + "intime", + "inutile", + "inventer", + "inviter", + "iode", + "iris", + "issue", + "ivre", + "jade", + "jadis", + "jamais", + "jambe", + "janvier", + "jardin", + "jauge", + "jaunisse", + "jeter", + "jeton", + "jeudi", + "jeune", + "joie", + "joindre", + "joli", + "joueur", + "journal", + "judo", + "juge", + "juillet", + "juin", + "jument", + "jungle", + "jupe", + "jupon", + "jurer", + "juron", + "jury", + "jusque", + "juste", + "kayak", + "ketchup", + "kilo", + "kiwi", + "koala", + "label", + "lacet", + "lacune", + "laine", + "laisse", + "lait", + "lame", + "lancer", + "lande", + "laque", + "lard", + "largeur", + "larme", + "larve", + "lasso", + "laver", + "lendemain", + "lentement", + "lequel", + "lettre", + "leur", + "lever", + "levure", + "liane", + "libre", + "lien", + "lier", + "lieutenant", + "ligne", + "ligoter", + "liguer", + "limace", + "limer", + "limite", + "lingot", + "lion", + "lire", + "lisser", + "litre", + "livre", + "lobe", + "local", + "logis", + "loin", + "loisir", + "long", + "loque", + "lors", + "lotus", + "louer", + "loup", + "lourd", + "louve", + "loyer", + "lubie", + "lucide", + "lueur", + "luge", + "luire", + "lundi", + "lune", + "lustre", + "lutin", + "lutte", + "luxe", + "machine", + "madame", + "magie", + "magnifique", + "magot", + "maigre", + "main", + "mairie", + "maison", + "malade", + "malheur", + "malin", + "manche", + "manger", + "manier", + "manoir", + "manquer", + "marche", + "mardi", + "marge", + "mariage", + "marquer", + "mars", + "masque", + "masse", + "matin", + "mauvais", + "meilleur", + "melon", + "membre", + "menacer", + "mener", + "mensonge", + "mentir", + "menu", + "merci", + "merlu", + "mesure", + "mettre", + "meuble", + "meunier", + "meute", + "miche", + "micro", + "midi", + "miel", + "miette", + "mieux", + "milieu", + "mille", + "mimer", + "mince", + "mineur", + "ministre", + "minute", + "mirage", + "miroir", + "miser", + "mite", + "mixte", + "mobile", + "mode", + "module", + "moins", + "mois", + "moment", + "momie", + "monde", + "monsieur", + "monter", + "moquer", + "moral", + "morceau", + "mordre", + "morose", + "morse", + "mortier", + "morue", + "motif", + "motte", + "moudre", + "moule", + "mourir", + "mousse", + "mouton", + "mouvement", + "moyen", + "muer", + "muette", + "mugir", + "muguet", + "mulot", + "multiple", + "munir", + "muret", + "muse", + "musique", + "muter", + "nacre", + "nager", + "nain", + "naissance", + "narine", + "narrer", + "naseau", + "nasse", + "nation", + "nature", + "naval", + "navet", + "naviguer", + "navrer", + "neige", + "nerf", + "nerveux", + "neuf", + "neutre", + "neuve", + "neveu", + "niche", + "nier", + "niveau", + "noble", + "noce", + "nocif", + "noir", + "nomade", + "nombre", + "nommer", + "nord", + "norme", + "notaire", + "notice", + "notre", + "nouer", + "nougat", + "nourrir", + "nous", + "nouveau", + "novice", + "noyade", + "noyer", + "nuage", + "nuance", + "nuire", + "nuit", + "nulle", + "nuque", + "oasis", + "objet", + "obliger", + "obscur", + "observer", + "obtenir", + "obus", + "occasion", + "occuper", + "ocre", + "octet", + "odeur", + "odorat", + "offense", + "officier", + "offrir", + "ogive", + "oiseau", + "olive", + "ombre", + "onctueux", + "onduler", + "ongle", + "onze", + "opter", + "option", + "orageux", + "oral", + "orange", + "orbite", + "ordinaire", + "ordre", + "oreille", + "organe", + "orgie", + "orgueil", + "orient", + "origan", + "orner", + "orteil", + "ortie", + "oser", + "osselet", + "otage", + "otarie", + "ouate", + "oublier", + "ouest", + "ours", + "outil", + "outre", + "ouvert", + "ouvrir", + "ovale", + "ozone", + "pacte", + "page", + "paille", + "pain", + "paire", + "paix", + "palace", + "palissade", + "palmier", + "palpiter", + "panda", + "panneau", + "papa", + "papier", + "paquet", + "parc", + "pardi", + "parfois", + "parler", + "parmi", + "parole", + "partir", + "parvenir", + "passer", + "pastel", + "patin", + "patron", + "paume", + "pause", + "pauvre", + "paver", + "pavot", + "payer", + "pays", + "peau", + "peigne", + "peinture", + "pelage", + "pelote", + "pencher", + "pendre", + "penser", + "pente", + "percer", + "perdu", + "perle", + "permettre", + "personne", + "perte", + "peser", + "pesticide", + "petit", + "peuple", + "peur", + "phase", + "photo", + "phrase", + "piano", + "pied", + "pierre", + "pieu", + "pile", + "pilier", + "pilote", + "pilule", + "piment", + "pincer", + "pinson", + "pinte", + "pion", + "piquer", + "pirate", + "pire", + "piste", + "piton", + "pitre", + "pivot", + "pizza", + "placer", + "plage", + "plaire", + "plan", + "plaque", + "plat", + "plein", + "pleurer", + "pliage", + "plier", + "plonger", + "plot", + "pluie", + "plume", + "plus", + "pneu", + "poche", + "podium", + "poids", + "poil", + "point", + "poire", + "poison", + "poitrine", + "poivre", + "police", + "pollen", + "pomme", + "pompier", + "poncer", + "pondre", + "pont", + "portion", + "poser", + "position", + "possible", + "poste", + "potage", + "potin", + "pouce", + "poudre", + "poulet", + "poumon", + "poupe", + "pour", + "pousser", + "poutre", + "pouvoir", + "prairie", + "premier", + "prendre", + "presque", + "preuve", + "prier", + "primeur", + "prince", + "prison", + "priver", + "prix", + "prochain", + "produire", + "profond", + "proie", + "projet", + "promener", + "prononcer", + "propre", + "prose", + "prouver", + "prune", + "public", + "puce", + "pudeur", + "puiser", + "pull", + "pulpe", + "puma", + "punir", + "purge", + "putois", + "quand", + "quartier", + "quasi", + "quatre", + "quel", + "question", + "queue", + "quiche", + "quille", + "quinze", + "quitter", + "quoi", + "rabais", + "raboter", + "race", + "racheter", + "racine", + "racler", + "raconter", + "radar", + "radio", + "rafale", + "rage", + "ragot", + "raideur", + "raie", + "rail", + "raison", + "ramasser", + "ramener", + "rampe", + "rance", + "rang", + "rapace", + "rapide", + "rapport", + "rarement", + "rasage", + "raser", + "rasoir", + "rassurer", + "rater", + "ratio", + "rature", + "ravage", + "ravir", + "rayer", + "rayon", + "rebond", + "recevoir", + "recherche", + "record", + "reculer", + "redevenir", + "refuser", + "regard", + "regretter", + "rein", + "rejeter", + "rejoindre", + "relation", + "relever", + "religion", + "remarquer", + "remettre", + "remise", + "remonter", + "remplir", + "remuer", + "rencontre", + "rendre", + "renier", + "renoncer", + "rentrer", + "renverser", + "repas", + "repli", + "reposer", + "reproche", + "requin", + "respect", + "ressembler", + "reste", + "retard", + "retenir", + "retirer", + "retour", + "retrouver", + "revenir", + "revoir", + "revue", + "rhume", + "ricaner", + "riche", + "rideau", + "ridicule", + "rien", + "rigide", + "rincer", + "rire", + "risquer", + "rituel", + "rivage", + "rive", + "robe", + "robot", + "robuste", + "rocade", + "roche", + "rodeur", + "rogner", + "roman", + "rompre", + "ronce", + "rondeur", + "ronger", + "roque", + "rose", + "rosir", + "rotation", + "rotule", + "roue", + "rouge", + "rouler", + "route", + "ruban", + "rubis", + "ruche", + "rude", + "ruelle", + "ruer", + "rugby", + "rugir", + "ruine", + "rumeur", + "rural", + "ruse", + "rustre", + "sable", + "sabot", + "sabre", + "sacre", + "sage", + "saint", + "saisir", + "salade", + "salive", + "salle", + "salon", + "salto", + "salut", + "salve", + "samba", + "sandale", + "sanguin", + "sapin", + "sarcasme", + "satisfaire", + "sauce", + "sauf", + "sauge", + "saule", + "sauna", + "sauter", + "sauver", + "savoir", + "science", + "scoop", + "score", + "second", + "secret", + "secte", + "seigneur", + "sein", + "seize", + "selle", + "selon", + "semaine", + "sembler", + "semer", + "semis", + "sensuel", + "sentir", + "sept", + "serpe", + "serrer", + "sertir", + "service", + "seuil", + "seulement", + "short", + "sien", + "sigle", + "signal", + "silence", + "silo", + "simple", + "singe", + "sinon", + "sinus", + "sioux", + "sirop", + "site", + "situation", + "skier", + "snob", + "sobre", + "social", + "socle", + "sodium", + "soigner", + "soir", + "soixante", + "soja", + "solaire", + "soldat", + "soleil", + "solide", + "solo", + "solvant", + "sombre", + "somme", + "somnoler", + "sondage", + "songeur", + "sonner", + "sorte", + "sosie", + "sottise", + "souci", + "soudain", + "souffrir", + "souhaiter", + "soulever", + "soumettre", + "soupe", + "sourd", + "soustraire", + "soutenir", + "souvent", + "soyeux", + "spectacle", + "sport", + "stade", + "stagiaire", + "stand", + "star", + "statue", + "stock", + "stop", + "store", + "style", + "suave", + "subir", + "sucre", + "suer", + "suffire", + "suie", + "suite", + "suivre", + "sujet", + "sulfite", + "supposer", + "surf", + "surprendre", + "surtout", + "surveiller", + "tabac", + "table", + "tabou", + "tache", + "tacler", + "tacot", + "tact", + "taie", + "taille", + "taire", + "talon", + "talus", + "tandis", + "tango", + "tanin", + "tant", + "taper", + "tapis", + "tard", + "tarif", + "tarot", + "tarte", + "tasse", + "taureau", + "taux", + "taverne", + "taxer", + "taxi", + "tellement", + "temple", + "tendre", + "tenir", + "tenter", + "tenu", + "terme", + "ternir", + "terre", + "test", + "texte", + "thym", + "tibia", + "tiers", + "tige", + "tipi", + "tique", + "tirer", + "tissu", + "titre", + "toast", + "toge", + "toile", + "toiser", + "toiture", + "tomber", + "tome", + "tonne", + "tonte", + "toque", + "torse", + "tortue", + "totem", + "toucher", + "toujours", + "tour", + "tousser", + "tout", + "toux", + "trace", + "train", + "trame", + "tranquille", + "travail", + "trembler", + "trente", + "tribu", + "trier", + "trio", + "tripe", + "triste", + "troc", + "trois", + "tromper", + "tronc", + "trop", + "trotter", + "trouer", + "truc", + "truite", + "tuba", + "tuer", + "tuile", + "turbo", + "tutu", + "tuyau", + "type", + "union", + "unique", + "unir", + "unisson", + "untel", + "urne", + "usage", + "user", + "usiner", + "usure", + "utile", + "vache", + "vague", + "vaincre", + "valeur", + "valoir", + "valser", + "valve", + "vampire", + "vaseux", + "vaste", + "veau", + "veille", + "veine", + "velours", + "velu", + "vendre", + "venir", + "vent", + "venue", + "verbe", + "verdict", + "version", + "vertige", + "verve", + "veste", + "veto", + "vexer", + "vice", + "victime", + "vide", + "vieil", + "vieux", + "vigie", + "vigne", + "ville", + "vingt", + "violent", + "virer", + "virus", + "visage", + "viser", + "visite", + "visuel", + "vitamine", + "vitrine", + "vivant", + "vivre", + "vocal", + "vodka", + "vogue", + "voici", + "voile", + "voir", + "voisin", + "voiture", + "volaille", + "volcan", + "voler", + "volt", + "votant", + "votre", + "vouer", + "vouloir", + "vous", + "voyage", + "voyou", + "vrac", + "vrai", + "yacht", + "yeti", + "yeux", + "yoga", + "zeste", + "zinc", + "zone", + "zoom" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/it.json b/coins/monero/src/wallet/seed/classic/it.json new file mode 100644 index 00000000..8c015c31 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/it.json @@ -0,0 +1,1628 @@ +[ + "abbinare", + "abbonato", + "abisso", + "abitare", + "abominio", + "accadere", + "accesso", + "acciaio", + "accordo", + "accumulo", + "acido", + "acqua", + "acrobata", + "acustico", + "adattare", + "addetto", + "addio", + "addome", + "adeguato", + "aderire", + "adorare", + "adottare", + "adozione", + "adulto", + "aereo", + "aerobica", + "affare", + "affetto", + "affidare", + "affogato", + "affronto", + "africano", + "afrodite", + "agenzia", + "aggancio", + "aggeggio", + "aggiunta", + "agio", + "agire", + "agitare", + "aglio", + "agnello", + "agosto", + "aiutare", + "albero", + "albo", + "alce", + "alchimia", + "alcool", + "alfabeto", + "algebra", + "alimento", + "allarme", + "alleanza", + "allievo", + "alloggio", + "alluce", + "alpi", + "alterare", + "altro", + "aluminio", + "amante", + "amarezza", + "ambiente", + "ambrosia", + "america", + "amico", + "ammalare", + "ammirare", + "amnesia", + "amnistia", + "amore", + "ampliare", + "amputare", + "analisi", + "anamnesi", + "ananas", + "anarchia", + "anatra", + "anca", + "ancorato", + "andare", + "androide", + "aneddoto", + "anello", + "angelo", + "angolino", + "anguilla", + "anidride", + "anima", + "annegare", + "anno", + "annuncio", + "anomalia", + "antenna", + "anticipo", + "aperto", + "apostolo", + "appalto", + "appello", + "appiglio", + "applauso", + "appoggio", + "appurare", + "aprile", + "aquila", + "arabo", + "arachidi", + "aragosta", + "arancia", + "arbitrio", + "archivio", + "arco", + "argento", + "argilla", + "aria", + "ariete", + "arma", + "armonia", + "aroma", + "arrivare", + "arrosto", + "arsenale", + "arte", + "artiglio", + "asfalto", + "asfissia", + "asino", + "asparagi", + "aspirina", + "assalire", + "assegno", + "assolto", + "assurdo", + "asta", + "astratto", + "atlante", + "atletica", + "atomo", + "atropina", + "attacco", + "attesa", + "attico", + "atto", + "attrarre", + "auguri", + "aula", + "aumento", + "aurora", + "auspicio", + "autista", + "auto", + "autunno", + "avanzare", + "avarizia", + "avere", + "aviatore", + "avido", + "avorio", + "avvenire", + "avviso", + "avvocato", + "azienda", + "azione", + "azzardo", + "azzurro", + "babbuino", + "bacio", + "badante", + "baffi", + "bagaglio", + "bagliore", + "bagno", + "balcone", + "balena", + "ballare", + "balordo", + "balsamo", + "bambola", + "bancomat", + "banda", + "barato", + "barba", + "barista", + "barriera", + "basette", + "basilico", + "bassista", + "bastare", + "battello", + "bavaglio", + "beccare", + "beduino", + "bellezza", + "bene", + "benzina", + "berretto", + "bestia", + "bevitore", + "bianco", + "bibbia", + "biberon", + "bibita", + "bici", + "bidone", + "bilancia", + "biliardo", + "binario", + "binocolo", + "biologia", + "biondina", + "biopsia", + "biossido", + "birbante", + "birra", + "biscotto", + "bisogno", + "bistecca", + "bivio", + "blindare", + "bloccare", + "bocca", + "bollire", + "bombola", + "bonifico", + "borghese", + "borsa", + "bottino", + "botulino", + "braccio", + "bradipo", + "branco", + "bravo", + "bresaola", + "bretelle", + "brevetto", + "briciola", + "brigante", + "brillare", + "brindare", + "brivido", + "broccoli", + "brontolo", + "bruciare", + "brufolo", + "bucare", + "buddista", + "budino", + "bufera", + "buffo", + "bugiardo", + "buio", + "buono", + "burrone", + "bussola", + "bustina", + "buttare", + "cabernet", + "cabina", + "cacao", + "cacciare", + "cactus", + "cadavere", + "caffe", + "calamari", + "calcio", + "caldaia", + "calmare", + "calunnia", + "calvario", + "calzone", + "cambiare", + "camera", + "camion", + "cammello", + "campana", + "canarino", + "cancello", + "candore", + "cane", + "canguro", + "cannone", + "canoa", + "cantare", + "canzone", + "caos", + "capanna", + "capello", + "capire", + "capo", + "capperi", + "capra", + "capsula", + "caraffa", + "carbone", + "carciofo", + "cardigan", + "carenza", + "caricare", + "carota", + "carrello", + "carta", + "casa", + "cascare", + "caserma", + "cashmere", + "casino", + "cassetta", + "castello", + "catalogo", + "catena", + "catorcio", + "cattivo", + "causa", + "cauzione", + "cavallo", + "caverna", + "caviglia", + "cavo", + "cazzotto", + "celibato", + "cemento", + "cenare", + "centrale", + "ceramica", + "cercare", + "ceretta", + "cerniera", + "certezza", + "cervello", + "cessione", + "cestino", + "cetriolo", + "chiave", + "chiedere", + "chilo", + "chimera", + "chiodo", + "chirurgo", + "chitarra", + "chiudere", + "ciabatta", + "ciao", + "cibo", + "ciccia", + "cicerone", + "ciclone", + "cicogna", + "cielo", + "cifra", + "cigno", + "ciliegia", + "cimitero", + "cinema", + "cinque", + "cintura", + "ciondolo", + "ciotola", + "cipolla", + "cippato", + "circuito", + "cisterna", + "citofono", + "ciuccio", + "civetta", + "civico", + "clausola", + "cliente", + "clima", + "clinica", + "cobra", + "coccole", + "cocktail", + "cocomero", + "codice", + "coesione", + "cogliere", + "cognome", + "colla", + "colomba", + "colpire", + "coltello", + "comando", + "comitato", + "commedia", + "comodino", + "compagna", + "comune", + "concerto", + "condotto", + "conforto", + "congiura", + "coniglio", + "consegna", + "conto", + "convegno", + "coperta", + "copia", + "coprire", + "corazza", + "corda", + "corleone", + "cornice", + "corona", + "corpo", + "corrente", + "corsa", + "cortesia", + "corvo", + "coso", + "costume", + "cotone", + "cottura", + "cozza", + "crampo", + "cratere", + "cravatta", + "creare", + "credere", + "crema", + "crescere", + "crimine", + "criterio", + "croce", + "crollare", + "cronaca", + "crostata", + "croupier", + "cubetto", + "cucciolo", + "cucina", + "cultura", + "cuoco", + "cuore", + "cupido", + "cupola", + "cura", + "curva", + "cuscino", + "custode", + "danzare", + "data", + "decennio", + "decidere", + "decollo", + "dedicare", + "dedurre", + "definire", + "delegare", + "delfino", + "delitto", + "demone", + "dentista", + "denuncia", + "deposito", + "derivare", + "deserto", + "designer", + "destino", + "detonare", + "dettagli", + "diagnosi", + "dialogo", + "diamante", + "diario", + "diavolo", + "dicembre", + "difesa", + "digerire", + "digitare", + "diluvio", + "dinamica", + "dipinto", + "diploma", + "diramare", + "dire", + "dirigere", + "dirupo", + "discesa", + "disdetta", + "disegno", + "disporre", + "dissenso", + "distacco", + "dito", + "ditta", + "diva", + "divenire", + "dividere", + "divorare", + "docente", + "dolcetto", + "dolore", + "domatore", + "domenica", + "dominare", + "donatore", + "donna", + "dorato", + "dormire", + "dorso", + "dosaggio", + "dottore", + "dovere", + "download", + "dragone", + "dramma", + "dubbio", + "dubitare", + "duetto", + "durata", + "ebbrezza", + "eccesso", + "eccitare", + "eclissi", + "economia", + "edera", + "edificio", + "editore", + "edizione", + "educare", + "effetto", + "egitto", + "egiziano", + "elastico", + "elefante", + "eleggere", + "elemento", + "elenco", + "elezione", + "elmetto", + "elogio", + "embrione", + "emergere", + "emettere", + "eminenza", + "emisfero", + "emozione", + "empatia", + "energia", + "enfasi", + "enigma", + "entrare", + "enzima", + "epidemia", + "epilogo", + "episodio", + "epoca", + "equivoco", + "erba", + "erede", + "eroe", + "erotico", + "errore", + "eruzione", + "esaltare", + "esame", + "esaudire", + "eseguire", + "esempio", + "esigere", + "esistere", + "esito", + "esperto", + "espresso", + "essere", + "estasi", + "esterno", + "estrarre", + "eterno", + "etica", + "euforico", + "europa", + "evacuare", + "evasione", + "evento", + "evidenza", + "evitare", + "evolvere", + "fabbrica", + "facciata", + "fagiano", + "fagotto", + "falco", + "fame", + "famiglia", + "fanale", + "fango", + "fantasia", + "farfalla", + "farmacia", + "faro", + "fase", + "fastidio", + "faticare", + "fatto", + "favola", + "febbre", + "femmina", + "femore", + "fenomeno", + "fermata", + "feromoni", + "ferrari", + "fessura", + "festa", + "fiaba", + "fiamma", + "fianco", + "fiat", + "fibbia", + "fidare", + "fieno", + "figa", + "figlio", + "figura", + "filetto", + "filmato", + "filosofo", + "filtrare", + "finanza", + "finestra", + "fingere", + "finire", + "finta", + "finzione", + "fiocco", + "fioraio", + "firewall", + "firmare", + "fisico", + "fissare", + "fittizio", + "fiume", + "flacone", + "flagello", + "flirtare", + "flusso", + "focaccia", + "foglio", + "fognario", + "follia", + "fonderia", + "fontana", + "forbici", + "forcella", + "foresta", + "forgiare", + "formare", + "fornace", + "foro", + "fortuna", + "forzare", + "fosforo", + "fotoni", + "fracasso", + "fragola", + "frantumi", + "fratello", + "frazione", + "freccia", + "freddo", + "frenare", + "fresco", + "friggere", + "frittata", + "frivolo", + "frizione", + "fronte", + "frullato", + "frumento", + "frusta", + "frutto", + "fucile", + "fuggire", + "fulmine", + "fumare", + "funzione", + "fuoco", + "furbizia", + "furgone", + "furia", + "furore", + "fusibile", + "fuso", + "futuro", + "gabbiano", + "galassia", + "gallina", + "gamba", + "gancio", + "garanzia", + "garofano", + "gasolio", + "gatto", + "gazebo", + "gazzetta", + "gelato", + "gemelli", + "generare", + "genitori", + "gennaio", + "geologia", + "germania", + "gestire", + "gettare", + "ghepardo", + "ghiaccio", + "giaccone", + "giaguaro", + "giallo", + "giappone", + "giardino", + "gigante", + "gioco", + "gioiello", + "giorno", + "giovane", + "giraffa", + "giudizio", + "giurare", + "giusto", + "globo", + "gloria", + "glucosio", + "gnocca", + "gocciola", + "godere", + "gomito", + "gomma", + "gonfiare", + "gorilla", + "governo", + "gradire", + "graffiti", + "granchio", + "grappolo", + "grasso", + "grattare", + "gridare", + "grissino", + "grondaia", + "grugnito", + "gruppo", + "guadagno", + "guaio", + "guancia", + "guardare", + "gufo", + "guidare", + "guscio", + "gusto", + "icona", + "idea", + "identico", + "idolo", + "idoneo", + "idrante", + "idrogeno", + "igiene", + "ignoto", + "imbarco", + "immagine", + "immobile", + "imparare", + "impedire", + "impianto", + "importo", + "impresa", + "impulso", + "incanto", + "incendio", + "incidere", + "incontro", + "incrocia", + "incubo", + "indagare", + "indice", + "indotto", + "infanzia", + "inferno", + "infinito", + "infranto", + "ingerire", + "inglese", + "ingoiare", + "ingresso", + "iniziare", + "innesco", + "insalata", + "inserire", + "insicuro", + "insonnia", + "insulto", + "interno", + "introiti", + "invasori", + "inverno", + "invito", + "invocare", + "ipnosi", + "ipocrita", + "ipotesi", + "ironia", + "irrigare", + "iscritto", + "isola", + "ispirare", + "isterico", + "istinto", + "istruire", + "italiano", + "jazz", + "labbra", + "labrador", + "ladro", + "lago", + "lamento", + "lampone", + "lancetta", + "lanterna", + "lapide", + "larva", + "lasagne", + "lasciare", + "lastra", + "latte", + "laurea", + "lavagna", + "lavorare", + "leccare", + "legare", + "leggere", + "lenzuolo", + "leone", + "lepre", + "letargo", + "lettera", + "levare", + "levitare", + "lezione", + "liberare", + "libidine", + "libro", + "licenza", + "lievito", + "limite", + "lince", + "lingua", + "liquore", + "lire", + "listino", + "litigare", + "litro", + "locale", + "lottare", + "lucciola", + "lucidare", + "luglio", + "luna", + "macchina", + "madama", + "madre", + "maestro", + "maggio", + "magico", + "maglione", + "magnolia", + "mago", + "maialino", + "maionese", + "malattia", + "male", + "malloppo", + "mancare", + "mandorla", + "mangiare", + "manico", + "manopola", + "mansarda", + "mantello", + "manubrio", + "manzo", + "mappa", + "mare", + "margine", + "marinaio", + "marmotta", + "marocco", + "martello", + "marzo", + "maschera", + "matrice", + "maturare", + "mazzetta", + "meandri", + "medaglia", + "medico", + "medusa", + "megafono", + "melone", + "membrana", + "menta", + "mercato", + "meritare", + "merluzzo", + "mese", + "mestiere", + "metafora", + "meteo", + "metodo", + "mettere", + "miele", + "miglio", + "miliardo", + "mimetica", + "minatore", + "minuto", + "miracolo", + "mirtillo", + "missile", + "mistero", + "misura", + "mito", + "mobile", + "moda", + "moderare", + "moglie", + "molecola", + "molle", + "momento", + "moneta", + "mongolia", + "monologo", + "montagna", + "morale", + "morbillo", + "mordere", + "mosaico", + "mosca", + "mostro", + "motivare", + "moto", + "mulino", + "mulo", + "muovere", + "muraglia", + "muscolo", + "museo", + "musica", + "mutande", + "nascere", + "nastro", + "natale", + "natura", + "nave", + "navigare", + "negare", + "negozio", + "nemico", + "nero", + "nervo", + "nessuno", + "nettare", + "neutroni", + "neve", + "nevicare", + "nicotina", + "nido", + "nipote", + "nocciola", + "noleggio", + "nome", + "nonno", + "norvegia", + "notare", + "notizia", + "nove", + "nucleo", + "nuda", + "nuotare", + "nutrire", + "obbligo", + "occhio", + "occupare", + "oceano", + "odissea", + "odore", + "offerta", + "officina", + "offrire", + "oggetto", + "oggi", + "olfatto", + "olio", + "oliva", + "ombelico", + "ombrello", + "omuncolo", + "ondata", + "onore", + "opera", + "opinione", + "opuscolo", + "opzione", + "orario", + "orbita", + "orchidea", + "ordine", + "orecchio", + "orgasmo", + "orgoglio", + "origine", + "orologio", + "oroscopo", + "orso", + "oscurare", + "ospedale", + "ospite", + "ossigeno", + "ostacolo", + "ostriche", + "ottenere", + "ottimo", + "ottobre", + "ovest", + "pacco", + "pace", + "pacifico", + "padella", + "pagare", + "pagina", + "pagnotta", + "palazzo", + "palestra", + "palpebre", + "pancetta", + "panfilo", + "panino", + "pannello", + "panorama", + "papa", + "paperino", + "paradiso", + "parcella", + "parente", + "parlare", + "parodia", + "parrucca", + "partire", + "passare", + "pasta", + "patata", + "patente", + "patogeno", + "patriota", + "pausa", + "pazienza", + "peccare", + "pecora", + "pedalare", + "pelare", + "pena", + "pendenza", + "penisola", + "pennello", + "pensare", + "pentirsi", + "percorso", + "perdono", + "perfetto", + "perizoma", + "perla", + "permesso", + "persona", + "pesare", + "pesce", + "peso", + "petardo", + "petrolio", + "pezzo", + "piacere", + "pianeta", + "piastra", + "piatto", + "piazza", + "piccolo", + "piede", + "piegare", + "pietra", + "pigiama", + "pigliare", + "pigrizia", + "pilastro", + "pilota", + "pinguino", + "pioggia", + "piombo", + "pionieri", + "piovra", + "pipa", + "pirata", + "pirolisi", + "piscina", + "pisolino", + "pista", + "pitone", + "piumino", + "pizza", + "plastica", + "platino", + "poesia", + "poiana", + "polaroid", + "polenta", + "polimero", + "pollo", + "polmone", + "polpetta", + "poltrona", + "pomodoro", + "pompa", + "popolo", + "porco", + "porta", + "porzione", + "possesso", + "postino", + "potassio", + "potere", + "poverino", + "pranzo", + "prato", + "prefisso", + "prelievo", + "premio", + "prendere", + "prestare", + "pretesa", + "prezzo", + "primario", + "privacy", + "problema", + "processo", + "prodotto", + "profeta", + "progetto", + "promessa", + "pronto", + "proposta", + "proroga", + "prossimo", + "proteina", + "prova", + "prudenza", + "pubblico", + "pudore", + "pugilato", + "pulire", + "pulsante", + "puntare", + "pupazzo", + "puzzle", + "quaderno", + "qualcuno", + "quarzo", + "quercia", + "quintale", + "rabbia", + "racconto", + "radice", + "raffica", + "ragazza", + "ragione", + "rammento", + "ramo", + "rana", + "randagio", + "rapace", + "rapinare", + "rapporto", + "rasatura", + "ravioli", + "reagire", + "realista", + "reattore", + "reazione", + "recitare", + "recluso", + "record", + "recupero", + "redigere", + "regalare", + "regina", + "regola", + "relatore", + "reliquia", + "remare", + "rendere", + "reparto", + "resina", + "resto", + "rete", + "retorica", + "rettile", + "revocare", + "riaprire", + "ribadire", + "ribelle", + "ricambio", + "ricetta", + "richiamo", + "ricordo", + "ridurre", + "riempire", + "riferire", + "riflesso", + "righello", + "rilancio", + "rilevare", + "rilievo", + "rimanere", + "rimborso", + "rinforzo", + "rinuncia", + "riparo", + "ripetere", + "riposare", + "ripulire", + "risalita", + "riscatto", + "riserva", + "riso", + "rispetto", + "ritaglio", + "ritmo", + "ritorno", + "ritratto", + "rituale", + "riunione", + "riuscire", + "riva", + "robotica", + "rondine", + "rosa", + "rospo", + "rosso", + "rotonda", + "rotta", + "roulotte", + "rubare", + "rubrica", + "ruffiano", + "rumore", + "ruota", + "ruscello", + "sabbia", + "sacco", + "saggio", + "sale", + "salire", + "salmone", + "salto", + "salutare", + "salvia", + "sangue", + "sanzioni", + "sapere", + "sapienza", + "sarcasmo", + "sardine", + "sartoria", + "sbalzo", + "sbarcare", + "sberla", + "sborsare", + "scadenza", + "scafo", + "scala", + "scambio", + "scappare", + "scarpa", + "scatola", + "scelta", + "scena", + "sceriffo", + "scheggia", + "schiuma", + "sciarpa", + "scienza", + "scimmia", + "sciopero", + "scivolo", + "sclerare", + "scolpire", + "sconto", + "scopa", + "scordare", + "scossa", + "scrivere", + "scrupolo", + "scuderia", + "scultore", + "scuola", + "scusare", + "sdraiare", + "secolo", + "sedativo", + "sedere", + "sedia", + "segare", + "segreto", + "seguire", + "semaforo", + "seme", + "senape", + "seno", + "sentiero", + "separare", + "sepolcro", + "sequenza", + "serata", + "serpente", + "servizio", + "sesso", + "seta", + "settore", + "sfamare", + "sfera", + "sfidare", + "sfiorare", + "sfogare", + "sgabello", + "sicuro", + "siepe", + "sigaro", + "silenzio", + "silicone", + "simbiosi", + "simpatia", + "simulare", + "sinapsi", + "sindrome", + "sinergia", + "sinonimo", + "sintonia", + "sirena", + "siringa", + "sistema", + "sito", + "smalto", + "smentire", + "smontare", + "soccorso", + "socio", + "soffitto", + "software", + "soggetto", + "sogliola", + "sognare", + "soldi", + "sole", + "sollievo", + "solo", + "sommario", + "sondare", + "sonno", + "sorpresa", + "sorriso", + "sospiro", + "sostegno", + "sovrano", + "spaccare", + "spada", + "spagnolo", + "spalla", + "sparire", + "spavento", + "spazio", + "specchio", + "spedire", + "spegnere", + "spendere", + "speranza", + "spessore", + "spezzare", + "spiaggia", + "spiccare", + "spiegare", + "spiffero", + "spingere", + "sponda", + "sporcare", + "spostare", + "spremuta", + "spugna", + "spumante", + "spuntare", + "squadra", + "squillo", + "staccare", + "stadio", + "stagione", + "stallone", + "stampa", + "stancare", + "starnuto", + "statura", + "stella", + "stendere", + "sterzo", + "stilista", + "stimolo", + "stinco", + "stiva", + "stoffa", + "storia", + "strada", + "stregone", + "striscia", + "studiare", + "stufa", + "stupendo", + "subire", + "successo", + "sudare", + "suono", + "superare", + "supporto", + "surfista", + "sussurro", + "svelto", + "svenire", + "sviluppo", + "svolta", + "svuotare", + "tabacco", + "tabella", + "tabu", + "tacchino", + "tacere", + "taglio", + "talento", + "tangente", + "tappeto", + "tartufo", + "tassello", + "tastiera", + "tavolo", + "tazza", + "teatro", + "tedesco", + "telaio", + "telefono", + "tema", + "temere", + "tempo", + "tendenza", + "tenebre", + "tensione", + "tentare", + "teologia", + "teorema", + "termica", + "terrazzo", + "teschio", + "tesi", + "tesoro", + "tessera", + "testa", + "thriller", + "tifoso", + "tigre", + "timbrare", + "timido", + "tinta", + "tirare", + "tisana", + "titano", + "titolo", + "toccare", + "togliere", + "topolino", + "torcia", + "torrente", + "tovaglia", + "traffico", + "tragitto", + "training", + "tramonto", + "transito", + "trapezio", + "trasloco", + "trattore", + "trazione", + "treccia", + "tregua", + "treno", + "triciclo", + "tridente", + "trilogia", + "tromba", + "troncare", + "trota", + "trovare", + "trucco", + "tubo", + "tulipano", + "tumulto", + "tunisia", + "tuono", + "turista", + "tuta", + "tutelare", + "tutore", + "ubriaco", + "uccello", + "udienza", + "udito", + "uffa", + "umanoide", + "umore", + "unghia", + "unguento", + "unicorno", + "unione", + "universo", + "uomo", + "uragano", + "uranio", + "urlare", + "uscire", + "utente", + "utilizzo", + "vacanza", + "vacca", + "vaglio", + "vagonata", + "valle", + "valore", + "valutare", + "valvola", + "vampiro", + "vaniglia", + "vanto", + "vapore", + "variante", + "vasca", + "vaselina", + "vassoio", + "vedere", + "vegetale", + "veglia", + "veicolo", + "vela", + "veleno", + "velivolo", + "velluto", + "vendere", + "venerare", + "venire", + "vento", + "veranda", + "verbo", + "verdura", + "vergine", + "verifica", + "vernice", + "vero", + "verruca", + "versare", + "vertebra", + "vescica", + "vespaio", + "vestito", + "vesuvio", + "veterano", + "vetro", + "vetta", + "viadotto", + "viaggio", + "vibrare", + "vicenda", + "vichingo", + "vietare", + "vigilare", + "vigneto", + "villa", + "vincere", + "violino", + "vipera", + "virgola", + "virtuoso", + "visita", + "vita", + "vitello", + "vittima", + "vivavoce", + "vivere", + "viziato", + "voglia", + "volare", + "volpe", + "volto", + "volume", + "vongole", + "voragine", + "vortice", + "votare", + "vulcano", + "vuotare", + "zabaione", + "zaffiro", + "zainetto", + "zampa", + "zanzara", + "zattera", + "zavorra", + "zenzero", + "zero", + "zingaro", + "zittire", + "zoccolo", + "zolfo", + "zombie", + "zucchero" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/ja.json b/coins/monero/src/wallet/seed/classic/ja.json new file mode 100644 index 00000000..439e6f72 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/ja.json @@ -0,0 +1,1628 @@ +[ + "あいこくしん", + "あいさつ", + "あいだ", + "あおぞら", + "あかちゃん", + "あきる", + "あけがた", + "あける", + "あこがれる", + "あさい", + "あさひ", + "あしあと", + "あじわう", + "あずかる", + "あずき", + "あそぶ", + "あたえる", + "あたためる", + "あたりまえ", + "あたる", + "あつい", + "あつかう", + "あっしゅく", + "あつまり", + "あつめる", + "あてな", + "あてはまる", + "あひる", + "あぶら", + "あぶる", + "あふれる", + "あまい", + "あまど", + "あまやかす", + "あまり", + "あみもの", + "あめりか", + "あやまる", + "あゆむ", + "あらいぐま", + "あらし", + "あらすじ", + "あらためる", + "あらゆる", + "あらわす", + "ありがとう", + "あわせる", + "あわてる", + "あんい", + "あんがい", + "あんこ", + "あんぜん", + "あんてい", + "あんない", + "あんまり", + "いいだす", + "いおん", + "いがい", + "いがく", + "いきおい", + "いきなり", + "いきもの", + "いきる", + "いくじ", + "いくぶん", + "いけばな", + "いけん", + "いこう", + "いこく", + "いこつ", + "いさましい", + "いさん", + "いしき", + "いじゅう", + "いじょう", + "いじわる", + "いずみ", + "いずれ", + "いせい", + "いせえび", + "いせかい", + "いせき", + "いぜん", + "いそうろう", + "いそがしい", + "いだい", + "いだく", + "いたずら", + "いたみ", + "いたりあ", + "いちおう", + "いちじ", + "いちど", + "いちば", + "いちぶ", + "いちりゅう", + "いつか", + "いっしゅん", + "いっせい", + "いっそう", + "いったん", + "いっち", + "いってい", + "いっぽう", + "いてざ", + "いてん", + "いどう", + "いとこ", + "いない", + "いなか", + "いねむり", + "いのち", + "いのる", + "いはつ", + "いばる", + "いはん", + "いびき", + "いひん", + "いふく", + "いへん", + "いほう", + "いみん", + "いもうと", + "いもたれ", + "いもり", + "いやがる", + "いやす", + "いよかん", + "いよく", + "いらい", + "いらすと", + "いりぐち", + "いりょう", + "いれい", + "いれもの", + "いれる", + "いろえんぴつ", + "いわい", + "いわう", + "いわかん", + "いわば", + "いわゆる", + "いんげんまめ", + "いんさつ", + "いんしょう", + "いんよう", + "うえき", + "うえる", + "うおざ", + "うがい", + "うかぶ", + "うかべる", + "うきわ", + "うくらいな", + "うくれれ", + "うけたまわる", + "うけつけ", + "うけとる", + "うけもつ", + "うける", + "うごかす", + "うごく", + "うこん", + "うさぎ", + "うしなう", + "うしろがみ", + "うすい", + "うすぎ", + "うすぐらい", + "うすめる", + "うせつ", + "うちあわせ", + "うちがわ", + "うちき", + "うちゅう", + "うっかり", + "うつくしい", + "うったえる", + "うつる", + "うどん", + "うなぎ", + "うなじ", + "うなずく", + "うなる", + "うねる", + "うのう", + "うぶげ", + "うぶごえ", + "うまれる", + "うめる", + "うもう", + "うやまう", + "うよく", + "うらがえす", + "うらぐち", + "うらない", + "うりあげ", + "うりきれ", + "うるさい", + "うれしい", + "うれゆき", + "うれる", + "うろこ", + "うわき", + "うわさ", + "うんこう", + "うんちん", + "うんてん", + "うんどう", + "えいえん", + "えいが", + "えいきょう", + "えいご", + "えいせい", + "えいぶん", + "えいよう", + "えいわ", + "えおり", + "えがお", + "えがく", + "えきたい", + "えくせる", + "えしゃく", + "えすて", + "えつらん", + "えのぐ", + "えほうまき", + "えほん", + "えまき", + "えもじ", + "えもの", + "えらい", + "えらぶ", + "えりあ", + "えんえん", + "えんかい", + "えんぎ", + "えんげき", + "えんしゅう", + "えんぜつ", + "えんそく", + "えんちょう", + "えんとつ", + "おいかける", + "おいこす", + "おいしい", + "おいつく", + "おうえん", + "おうさま", + "おうじ", + "おうせつ", + "おうたい", + "おうふく", + "おうべい", + "おうよう", + "おえる", + "おおい", + "おおう", + "おおどおり", + "おおや", + "おおよそ", + "おかえり", + "おかず", + "おがむ", + "おかわり", + "おぎなう", + "おきる", + "おくさま", + "おくじょう", + "おくりがな", + "おくる", + "おくれる", + "おこす", + "おこなう", + "おこる", + "おさえる", + "おさない", + "おさめる", + "おしいれ", + "おしえる", + "おじぎ", + "おじさん", + "おしゃれ", + "おそらく", + "おそわる", + "おたがい", + "おたく", + "おだやか", + "おちつく", + "おっと", + "おつり", + "おでかけ", + "おとしもの", + "おとなしい", + "おどり", + "おどろかす", + "おばさん", + "おまいり", + "おめでとう", + "おもいで", + "おもう", + "おもたい", + "おもちゃ", + "おやつ", + "おやゆび", + "およぼす", + "おらんだ", + "おろす", + "おんがく", + "おんけい", + "おんしゃ", + "おんせん", + "おんだん", + "おんちゅう", + "おんどけい", + "かあつ", + "かいが", + "がいき", + "がいけん", + "がいこう", + "かいさつ", + "かいしゃ", + "かいすいよく", + "かいぜん", + "かいぞうど", + "かいつう", + "かいてん", + "かいとう", + "かいふく", + "がいへき", + "かいほう", + "かいよう", + "がいらい", + "かいわ", + "かえる", + "かおり", + "かかえる", + "かがく", + "かがし", + "かがみ", + "かくご", + "かくとく", + "かざる", + "がぞう", + "かたい", + "かたち", + "がちょう", + "がっきゅう", + "がっこう", + "がっさん", + "がっしょう", + "かなざわし", + "かのう", + "がはく", + "かぶか", + "かほう", + "かほご", + "かまう", + "かまぼこ", + "かめれおん", + "かゆい", + "かようび", + "からい", + "かるい", + "かろう", + "かわく", + "かわら", + "がんか", + "かんけい", + "かんこう", + "かんしゃ", + "かんそう", + "かんたん", + "かんち", + "がんばる", + "きあい", + "きあつ", + "きいろ", + "ぎいん", + "きうい", + "きうん", + "きえる", + "きおう", + "きおく", + "きおち", + "きおん", + "きかい", + "きかく", + "きかんしゃ", + "ききて", + "きくばり", + "きくらげ", + "きけんせい", + "きこう", + "きこえる", + "きこく", + "きさい", + "きさく", + "きさま", + "きさらぎ", + "ぎじかがく", + "ぎしき", + "ぎじたいけん", + "ぎじにってい", + "ぎじゅつしゃ", + "きすう", + "きせい", + "きせき", + "きせつ", + "きそう", + "きぞく", + "きぞん", + "きたえる", + "きちょう", + "きつえん", + "ぎっちり", + "きつつき", + "きつね", + "きてい", + "きどう", + "きどく", + "きない", + "きなが", + "きなこ", + "きぬごし", + "きねん", + "きのう", + "きのした", + "きはく", + "きびしい", + "きひん", + "きふく", + "きぶん", + "きぼう", + "きほん", + "きまる", + "きみつ", + "きむずかしい", + "きめる", + "きもだめし", + "きもち", + "きもの", + "きゃく", + "きやく", + "ぎゅうにく", + "きよう", + "きょうりゅう", + "きらい", + "きらく", + "きりん", + "きれい", + "きれつ", + "きろく", + "ぎろん", + "きわめる", + "ぎんいろ", + "きんかくじ", + "きんじょ", + "きんようび", + "ぐあい", + "くいず", + "くうかん", + "くうき", + "くうぐん", + "くうこう", + "ぐうせい", + "くうそう", + "ぐうたら", + "くうふく", + "くうぼ", + "くかん", + "くきょう", + "くげん", + "ぐこう", + "くさい", + "くさき", + "くさばな", + "くさる", + "くしゃみ", + "くしょう", + "くすのき", + "くすりゆび", + "くせげ", + "くせん", + "ぐたいてき", + "くださる", + "くたびれる", + "くちこみ", + "くちさき", + "くつした", + "ぐっすり", + "くつろぐ", + "くとうてん", + "くどく", + "くなん", + "くねくね", + "くのう", + "くふう", + "くみあわせ", + "くみたてる", + "くめる", + "くやくしょ", + "くらす", + "くらべる", + "くるま", + "くれる", + "くろう", + "くわしい", + "ぐんかん", + "ぐんしょく", + "ぐんたい", + "ぐんて", + "けあな", + "けいかく", + "けいけん", + "けいこ", + "けいさつ", + "げいじゅつ", + "けいたい", + "げいのうじん", + "けいれき", + "けいろ", + "けおとす", + "けおりもの", + "げきか", + "げきげん", + "げきだん", + "げきちん", + "げきとつ", + "げきは", + "げきやく", + "げこう", + "げこくじょう", + "げざい", + "けさき", + "げざん", + "けしき", + "けしごむ", + "けしょう", + "げすと", + "けたば", + "けちゃっぷ", + "けちらす", + "けつあつ", + "けつい", + "けつえき", + "けっこん", + "けつじょ", + "けっせき", + "けってい", + "けつまつ", + "げつようび", + "げつれい", + "けつろん", + "げどく", + "けとばす", + "けとる", + "けなげ", + "けなす", + "けなみ", + "けぬき", + "げねつ", + "けねん", + "けはい", + "げひん", + "けぶかい", + "げぼく", + "けまり", + "けみかる", + "けむし", + "けむり", + "けもの", + "けらい", + "けろけろ", + "けわしい", + "けんい", + "けんえつ", + "けんお", + "けんか", + "げんき", + "けんげん", + "けんこう", + "けんさく", + "けんしゅう", + "けんすう", + "げんそう", + "けんちく", + "けんてい", + "けんとう", + "けんない", + "けんにん", + "げんぶつ", + "けんま", + "けんみん", + "けんめい", + "けんらん", + "けんり", + "こあくま", + "こいぬ", + "こいびと", + "ごうい", + "こうえん", + "こうおん", + "こうかん", + "ごうきゅう", + "ごうけい", + "こうこう", + "こうさい", + "こうじ", + "こうすい", + "ごうせい", + "こうそく", + "こうたい", + "こうちゃ", + "こうつう", + "こうてい", + "こうどう", + "こうない", + "こうはい", + "ごうほう", + "ごうまん", + "こうもく", + "こうりつ", + "こえる", + "こおり", + "ごかい", + "ごがつ", + "ごかん", + "こくご", + "こくさい", + "こくとう", + "こくない", + "こくはく", + "こぐま", + "こけい", + "こける", + "ここのか", + "こころ", + "こさめ", + "こしつ", + "こすう", + "こせい", + "こせき", + "こぜん", + "こそだて", + "こたい", + "こたえる", + "こたつ", + "こちょう", + "こっか", + "こつこつ", + "こつばん", + "こつぶ", + "こてい", + "こてん", + "ことがら", + "ことし", + "ことば", + "ことり", + "こなごな", + "こねこね", + "このまま", + "このみ", + "このよ", + "ごはん", + "こひつじ", + "こふう", + "こふん", + "こぼれる", + "ごまあぶら", + "こまかい", + "ごますり", + "こまつな", + "こまる", + "こむぎこ", + "こもじ", + "こもち", + "こもの", + "こもん", + "こやく", + "こやま", + "こゆう", + "こゆび", + "こよい", + "こよう", + "こりる", + "これくしょん", + "ころっけ", + "こわもて", + "こわれる", + "こんいん", + "こんかい", + "こんき", + "こんしゅう", + "こんすい", + "こんだて", + "こんとん", + "こんなん", + "こんびに", + "こんぽん", + "こんまけ", + "こんや", + "こんれい", + "こんわく", + "ざいえき", + "さいかい", + "さいきん", + "ざいげん", + "ざいこ", + "さいしょ", + "さいせい", + "ざいたく", + "ざいちゅう", + "さいてき", + "ざいりょう", + "さうな", + "さかいし", + "さがす", + "さかな", + "さかみち", + "さがる", + "さぎょう", + "さくし", + "さくひん", + "さくら", + "さこく", + "さこつ", + "さずかる", + "ざせき", + "さたん", + "さつえい", + "ざつおん", + "ざっか", + "ざつがく", + "さっきょく", + "ざっし", + "さつじん", + "ざっそう", + "さつたば", + "さつまいも", + "さてい", + "さといも", + "さとう", + "さとおや", + "さとし", + "さとる", + "さのう", + "さばく", + "さびしい", + "さべつ", + "さほう", + "さほど", + "さます", + "さみしい", + "さみだれ", + "さむけ", + "さめる", + "さやえんどう", + "さゆう", + "さよう", + "さよく", + "さらだ", + "ざるそば", + "さわやか", + "さわる", + "さんいん", + "さんか", + "さんきゃく", + "さんこう", + "さんさい", + "ざんしょ", + "さんすう", + "さんせい", + "さんそ", + "さんち", + "さんま", + "さんみ", + "さんらん", + "しあい", + "しあげ", + "しあさって", + "しあわせ", + "しいく", + "しいん", + "しうち", + "しえい", + "しおけ", + "しかい", + "しかく", + "じかん", + "しごと", + "しすう", + "じだい", + "したうけ", + "したぎ", + "したて", + "したみ", + "しちょう", + "しちりん", + "しっかり", + "しつじ", + "しつもん", + "してい", + "してき", + "してつ", + "じてん", + "じどう", + "しなぎれ", + "しなもの", + "しなん", + "しねま", + "しねん", + "しのぐ", + "しのぶ", + "しはい", + "しばかり", + "しはつ", + "しはらい", + "しはん", + "しひょう", + "しふく", + "じぶん", + "しへい", + "しほう", + "しほん", + "しまう", + "しまる", + "しみん", + "しむける", + "じむしょ", + "しめい", + "しめる", + "しもん", + "しゃいん", + "しゃうん", + "しゃおん", + "じゃがいも", + "しやくしょ", + "しゃくほう", + "しゃけん", + "しゃこ", + "しゃざい", + "しゃしん", + "しゃせん", + "しゃそう", + "しゃたい", + "しゃちょう", + "しゃっきん", + "じゃま", + "しゃりん", + "しゃれい", + "じゆう", + "じゅうしょ", + "しゅくはく", + "じゅしん", + "しゅっせき", + "しゅみ", + "しゅらば", + "じゅんばん", + "しょうかい", + "しょくたく", + "しょっけん", + "しょどう", + "しょもつ", + "しらせる", + "しらべる", + "しんか", + "しんこう", + "じんじゃ", + "しんせいじ", + "しんちく", + "しんりん", + "すあげ", + "すあし", + "すあな", + "ずあん", + "すいえい", + "すいか", + "すいとう", + "ずいぶん", + "すいようび", + "すうがく", + "すうじつ", + "すうせん", + "すおどり", + "すきま", + "すくう", + "すくない", + "すける", + "すごい", + "すこし", + "ずさん", + "すずしい", + "すすむ", + "すすめる", + "すっかり", + "ずっしり", + "ずっと", + "すてき", + "すてる", + "すねる", + "すのこ", + "すはだ", + "すばらしい", + "ずひょう", + "ずぶぬれ", + "すぶり", + "すふれ", + "すべて", + "すべる", + "ずほう", + "すぼん", + "すまい", + "すめし", + "すもう", + "すやき", + "すらすら", + "するめ", + "すれちがう", + "すろっと", + "すわる", + "すんぜん", + "すんぽう", + "せあぶら", + "せいかつ", + "せいげん", + "せいじ", + "せいよう", + "せおう", + "せかいかん", + "せきにん", + "せきむ", + "せきゆ", + "せきらんうん", + "せけん", + "せこう", + "せすじ", + "せたい", + "せたけ", + "せっかく", + "せっきゃく", + "ぜっく", + "せっけん", + "せっこつ", + "せっさたくま", + "せつぞく", + "せつだん", + "せつでん", + "せっぱん", + "せつび", + "せつぶん", + "せつめい", + "せつりつ", + "せなか", + "せのび", + "せはば", + "せびろ", + "せぼね", + "せまい", + "せまる", + "せめる", + "せもたれ", + "せりふ", + "ぜんあく", + "せんい", + "せんえい", + "せんか", + "せんきょ", + "せんく", + "せんげん", + "ぜんご", + "せんさい", + "せんしゅ", + "せんすい", + "せんせい", + "せんぞ", + "せんたく", + "せんちょう", + "せんてい", + "せんとう", + "せんぬき", + "せんねん", + "せんぱい", + "ぜんぶ", + "ぜんぽう", + "せんむ", + "せんめんじょ", + "せんもん", + "せんやく", + "せんゆう", + "せんよう", + "ぜんら", + "ぜんりゃく", + "せんれい", + "せんろ", + "そあく", + "そいとげる", + "そいね", + "そうがんきょう", + "そうき", + "そうご", + "そうしん", + "そうだん", + "そうなん", + "そうび", + "そうめん", + "そうり", + "そえもの", + "そえん", + "そがい", + "そげき", + "そこう", + "そこそこ", + "そざい", + "そしな", + "そせい", + "そせん", + "そそぐ", + "そだてる", + "そつう", + "そつえん", + "そっかん", + "そつぎょう", + "そっけつ", + "そっこう", + "そっせん", + "そっと", + "そとがわ", + "そとづら", + "そなえる", + "そなた", + "そふぼ", + "そぼく", + "そぼろ", + "そまつ", + "そまる", + "そむく", + "そむりえ", + "そめる", + "そもそも", + "そよかぜ", + "そらまめ", + "そろう", + "そんかい", + "そんけい", + "そんざい", + "そんしつ", + "そんぞく", + "そんちょう", + "ぞんび", + "ぞんぶん", + "そんみん", + "たあい", + "たいいん", + "たいうん", + "たいえき", + "たいおう", + "だいがく", + "たいき", + "たいぐう", + "たいけん", + "たいこ", + "たいざい", + "だいじょうぶ", + "だいすき", + "たいせつ", + "たいそう", + "だいたい", + "たいちょう", + "たいてい", + "だいどころ", + "たいない", + "たいねつ", + "たいのう", + "たいはん", + "だいひょう", + "たいふう", + "たいへん", + "たいほ", + "たいまつばな", + "たいみんぐ", + "たいむ", + "たいめん", + "たいやき", + "たいよう", + "たいら", + "たいりょく", + "たいる", + "たいわん", + "たうえ", + "たえる", + "たおす", + "たおる", + "たおれる", + "たかい", + "たかね", + "たきび", + "たくさん", + "たこく", + "たこやき", + "たさい", + "たしざん", + "だじゃれ", + "たすける", + "たずさわる", + "たそがれ", + "たたかう", + "たたく", + "ただしい", + "たたみ", + "たちばな", + "だっかい", + "だっきゃく", + "だっこ", + "だっしゅつ", + "だったい", + "たてる", + "たとえる", + "たなばた", + "たにん", + "たぬき", + "たのしみ", + "たはつ", + "たぶん", + "たべる", + "たぼう", + "たまご", + "たまる", + "だむる", + "ためいき", + "ためす", + "ためる", + "たもつ", + "たやすい", + "たよる", + "たらす", + "たりきほんがん", + "たりょう", + "たりる", + "たると", + "たれる", + "たれんと", + "たろっと", + "たわむれる", + "だんあつ", + "たんい", + "たんおん", + "たんか", + "たんき", + "たんけん", + "たんご", + "たんさん", + "たんじょうび", + "だんせい", + "たんそく", + "たんたい", + "だんち", + "たんてい", + "たんとう", + "だんな", + "たんにん", + "だんねつ", + "たんのう", + "たんぴん", + "だんぼう", + "たんまつ", + "たんめい", + "だんれつ", + "だんろ", + "だんわ", + "ちあい", + "ちあん", + "ちいき", + "ちいさい", + "ちえん", + "ちかい", + "ちから", + "ちきゅう", + "ちきん", + "ちけいず", + "ちけん", + "ちこく", + "ちさい", + "ちしき", + "ちしりょう", + "ちせい", + "ちそう", + "ちたい", + "ちたん", + "ちちおや", + "ちつじょ", + "ちてき", + "ちてん", + "ちぬき", + "ちぬり", + "ちのう", + "ちひょう", + "ちへいせん", + "ちほう", + "ちまた", + "ちみつ", + "ちみどろ", + "ちめいど", + "ちゃんこなべ", + "ちゅうい", + "ちゆりょく", + "ちょうし", + "ちょさくけん", + "ちらし", + "ちらみ", + "ちりがみ", + "ちりょう", + "ちるど", + "ちわわ", + "ちんたい", + "ちんもく", + "ついか", + "ついたち", + "つうか", + "つうじょう", + "つうはん", + "つうわ", + "つかう", + "つかれる", + "つくね", + "つくる", + "つけね", + "つける", + "つごう", + "つたえる", + "つづく", + "つつじ", + "つつむ", + "つとめる", + "つながる", + "つなみ", + "つねづね", + "つのる", + "つぶす", + "つまらない", + "つまる", + "つみき", + "つめたい", + "つもり", + "つもる", + "つよい", + "つるぼ", + "つるみく", + "つわもの", + "つわり", + "てあし", + "てあて", + "てあみ", + "ていおん", + "ていか", + "ていき", + "ていけい", + "ていこく", + "ていさつ", + "ていし", + "ていせい", + "ていたい", + "ていど", + "ていねい", + "ていひょう", + "ていへん", + "ていぼう", + "てうち", + "ておくれ", + "てきとう", + "てくび", + "でこぼこ", + "てさぎょう", + "てさげ", + "てすり", + "てそう", + "てちがい", + "てちょう", + "てつがく", + "てつづき", + "でっぱ", + "てつぼう", + "てつや", + "でぬかえ", + "てぬき", + "てぬぐい", + "てのひら", + "てはい", + "てぶくろ", + "てふだ", + "てほどき", + "てほん", + "てまえ", + "てまきずし", + "てみじか", + "てみやげ", + "てらす", + "てれび", + "てわけ", + "てわたし", + "でんあつ", + "てんいん", + "てんかい", + "てんき", + "てんぐ", + "てんけん", + "てんごく", + "てんさい", + "てんし", + "てんすう", + "でんち", + "てんてき", + "てんとう", + "てんない", + "てんぷら", + "てんぼうだい", + "てんめつ", + "てんらんかい", + "でんりょく", + "でんわ", + "どあい", + "といれ", + "どうかん", + "とうきゅう", + "どうぐ", + "とうし", + "とうむぎ", + "とおい", + "とおか", + "とおく", + "とおす", + "とおる", + "とかい", + "とかす", + "ときおり", + "ときどき", + "とくい", + "とくしゅう", + "とくてん", + "とくに", + "とくべつ", + "とけい", + "とける", + "とこや", + "とさか", + "としょかん", + "とそう", + "とたん", + "とちゅう", + "とっきゅう", + "とっくん", + "とつぜん", + "とつにゅう", + "とどける", + "ととのえる", + "とない", + "となえる", + "となり", + "とのさま", + "とばす", + "どぶがわ", + "とほう", + "とまる", + "とめる", + "ともだち", + "ともる", + "どようび", + "とらえる", + "とんかつ", + "どんぶり", + "ないかく", + "ないこう", + "ないしょ", + "ないす", + "ないせん", + "ないそう", + "なおす", + "ながい", + "なくす", + "なげる", + "なこうど", + "なさけ", + "なたでここ", + "なっとう", + "なつやすみ", + "ななおし", + "なにごと", + "なにもの", + "なにわ", + "なのか", + "なふだ", + "なまいき", + "なまえ", + "なまみ", + "なみだ", + "なめらか", + "なめる", + "なやむ", + "ならう", + "ならび", + "ならぶ", + "なれる", + "なわとび", + "なわばり", + "にあう", + "にいがた", + "にうけ", + "におい", + "にかい", + "にがて", + "にきび", + "にくしみ", + "にくまん", + "にげる", + "にさんかたんそ", + "にしき", + "にせもの", + "にちじょう", + "にちようび", + "にっか", + "にっき", + "にっけい", + "にっこう", + "にっさん", + "にっしょく", + "にっすう", + "にっせき", + "にってい", + "になう", + "にほん", + "にまめ", + "にもつ", + "にやり", + "にゅういん", + "にりんしゃ", + "にわとり", + "にんい", + "にんか", + "にんき", + "にんげん", + "にんしき", + "にんずう", + "にんそう", + "にんたい", + "にんち", + "にんてい", + "にんにく", + "にんぷ", + "にんまり", + "にんむ", + "にんめい", + "にんよう", + "ぬいくぎ", + "ぬかす", + "ぬぐいとる", + "ぬぐう", + "ぬくもり", + "ぬすむ", + "ぬまえび", + "ぬめり", + "ぬらす", + "ぬんちゃく", + "ねあげ", + "ねいき", + "ねいる", + "ねいろ", + "ねぐせ", + "ねくたい", + "ねくら", + "ねこぜ", + "ねこむ", + "ねさげ", + "ねすごす", + "ねそべる", + "ねだん", + "ねつい", + "ねっしん", + "ねつぞう", + "ねったいぎょ", + "ねぶそく", + "ねふだ", + "ねぼう", + "ねほりはほり", + "ねまき", + "ねまわし", + "ねみみ", + "ねむい", + "ねむたい", + "ねもと", + "ねらう", + "ねわざ", + "ねんいり", + "ねんおし", + "ねんかん", + "ねんきん", + "ねんぐ", + "ねんざ", + "ねんし", + "ねんちゃく", + "ねんど", + "ねんぴ", + "ねんぶつ", + "ねんまつ", + "ねんりょう", + "ねんれい", + "のいず", + "のおづま", + "のがす", + "のきなみ", + "のこぎり", + "のこす", + "のこる", + "のせる", + "のぞく", + "のぞむ", + "のたまう", + "のちほど", + "のっく", + "のばす", + "のはら", + "のべる", + "のぼる", + "のみもの", + "のやま", + "のらいぬ", + "のらねこ", + "のりもの", + "のりゆき", + "のれん", + "のんき", + "ばあい", + "はあく", + "ばあさん", + "ばいか", + "ばいく", + "はいけん", + "はいご", + "はいしん", + "はいすい", + "はいせん", + "はいそう", + "はいち", + "ばいばい", + "はいれつ", + "はえる", + "はおる", + "はかい", + "ばかり", + "はかる", + "はくしゅ", + "はけん", + "はこぶ", + "はさみ", + "はさん", + "はしご", + "ばしょ", + "はしる", + "はせる", + "ぱそこん", + "はそん", + "はたん", + "はちみつ", + "はつおん", + "はっかく", + "はづき", + "はっきり", + "はっくつ", + "はっけん", + "はっこう", + "はっさん", + "はっしん", + "はったつ", + "はっちゅう", + "はってん", + "はっぴょう", + "はっぽう", + "はなす", + "はなび", + "はにかむ", + "はぶらし", + "はみがき", + "はむかう", + "はめつ", + "はやい", + "はやし", + "はらう", + "はろうぃん", + "はわい", + "はんい", + "はんえい", + "はんおん", + "はんかく", + "はんきょう", + "ばんぐみ", + "はんこ", + "はんしゃ", + "はんすう", + "はんだん", + "ぱんち", + "ぱんつ", + "はんてい", + "はんとし", + "はんのう", + "はんぱ", + "はんぶん", + "はんぺん", + "はんぼうき", + "はんめい", + "はんらん", + "はんろん", + "ひいき", + "ひうん", + "ひえる", + "ひかく", + "ひかり", + "ひかる", + "ひかん", + "ひくい", + "ひけつ", + "ひこうき", + "ひこく", + "ひさい", + "ひさしぶり", + "ひさん", + "びじゅつかん", + "ひしょ" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/jbo.json b/coins/monero/src/wallet/seed/classic/jbo.json new file mode 100644 index 00000000..ccd02d02 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/jbo.json @@ -0,0 +1,1628 @@ +[ + "backi", + "bacru", + "badna", + "badri", + "bajra", + "bakfu", + "bakni", + "bakri", + "baktu", + "balji", + "balni", + "balre", + "balvi", + "bambu", + "bancu", + "bandu", + "banfi", + "bangu", + "banli", + "banro", + "banxa", + "banzu", + "bapli", + "barda", + "bargu", + "barja", + "barna", + "bartu", + "basfa", + "basna", + "basti", + "batci", + "batke", + "bavmi", + "baxso", + "bebna", + "bekpi", + "bemro", + "bende", + "bengo", + "benji", + "benre", + "benzo", + "bergu", + "bersa", + "berti", + "besna", + "besto", + "betfu", + "betri", + "bevri", + "bidju", + "bifce", + "bikla", + "bilga", + "bilma", + "bilni", + "bindo", + "binra", + "binxo", + "birje", + "birka", + "birti", + "bisli", + "bitmu", + "bitni", + "blabi", + "blaci", + "blanu", + "bliku", + "bloti", + "bolci", + "bongu", + "boske", + "botpi", + "boxfo", + "boxna", + "bradi", + "brano", + "bratu", + "brazo", + "bredi", + "bridi", + "brife", + "briju", + "brito", + "brivo", + "broda", + "bruna", + "budjo", + "bukpu", + "bumru", + "bunda", + "bunre", + "burcu", + "burna", + "cabna", + "cabra", + "cacra", + "cadga", + "cadzu", + "cafne", + "cagna", + "cakla", + "calku", + "calse", + "canci", + "cando", + "cange", + "canja", + "canko", + "canlu", + "canpa", + "canre", + "canti", + "carce", + "carfu", + "carmi", + "carna", + "cartu", + "carvi", + "casnu", + "catke", + "catlu", + "catni", + "catra", + "caxno", + "cecla", + "cecmu", + "cedra", + "cenba", + "censa", + "centi", + "cerda", + "cerni", + "certu", + "cevni", + "cfale", + "cfari", + "cfika", + "cfila", + "cfine", + "cfipu", + "ciblu", + "cicna", + "cidja", + "cidni", + "cidro", + "cifnu", + "cigla", + "cikna", + "cikre", + "ciksi", + "cilce", + "cilfu", + "cilmo", + "cilre", + "cilta", + "cimde", + "cimni", + "cinba", + "cindu", + "cinfo", + "cinje", + "cinki", + "cinla", + "cinmo", + "cinri", + "cinse", + "cinta", + "cinza", + "cipni", + "cipra", + "cirko", + "cirla", + "ciska", + "cisma", + "cisni", + "ciste", + "citka", + "citno", + "citri", + "citsi", + "civla", + "cizra", + "ckabu", + "ckafi", + "ckaji", + "ckana", + "ckape", + "ckasu", + "ckeji", + "ckiku", + "ckilu", + "ckini", + "ckire", + "ckule", + "ckunu", + "cladu", + "clani", + "claxu", + "cletu", + "clika", + "clinu", + "clira", + "clite", + "cliva", + "clupa", + "cmaci", + "cmalu", + "cmana", + "cmavo", + "cmene", + "cmeta", + "cmevo", + "cmila", + "cmima", + "cmoni", + "cnano", + "cnebo", + "cnemu", + "cnici", + "cnino", + "cnisa", + "cnita", + "cokcu", + "condi", + "conka", + "corci", + "cortu", + "cpacu", + "cpana", + "cpare", + "cpedu", + "cpina", + "cradi", + "crane", + "creka", + "crepu", + "cribe", + "crida", + "crino", + "cripu", + "crisa", + "critu", + "ctaru", + "ctebi", + "cteki", + "ctile", + "ctino", + "ctuca", + "cukla", + "cukre", + "cukta", + "culno", + "cumki", + "cumla", + "cunmi", + "cunso", + "cuntu", + "cupra", + "curmi", + "curnu", + "curve", + "cusku", + "cusna", + "cutci", + "cutne", + "cuxna", + "dacru", + "dacti", + "dadjo", + "dakfu", + "dakli", + "damba", + "damri", + "dandu", + "danfu", + "danlu", + "danmo", + "danre", + "dansu", + "danti", + "daplu", + "dapma", + "darca", + "dargu", + "darlu", + "darno", + "darsi", + "darxi", + "daski", + "dasni", + "daspo", + "dasri", + "datka", + "datni", + "datro", + "decti", + "degji", + "dejni", + "dekpu", + "dekto", + "delno", + "dembi", + "denci", + "denmi", + "denpa", + "dertu", + "derxi", + "desku", + "detri", + "dicma", + "dicra", + "didni", + "digno", + "dikca", + "diklo", + "dikni", + "dilcu", + "dilma", + "dilnu", + "dimna", + "dindi", + "dinju", + "dinko", + "dinso", + "dirba", + "dirce", + "dirgo", + "disko", + "ditcu", + "divzi", + "dizlo", + "djacu", + "djedi", + "djica", + "djine", + "djuno", + "donri", + "dotco", + "draci", + "drani", + "drata", + "drudi", + "dugri", + "dukse", + "dukti", + "dunda", + "dunja", + "dunku", + "dunli", + "dunra", + "dutso", + "dzena", + "dzipo", + "facki", + "fadni", + "fagri", + "falnu", + "famti", + "fancu", + "fange", + "fanmo", + "fanri", + "fanta", + "fanva", + "fanza", + "fapro", + "farka", + "farlu", + "farna", + "farvi", + "fasnu", + "fatci", + "fatne", + "fatri", + "febvi", + "fegli", + "femti", + "fendi", + "fengu", + "fenki", + "fenra", + "fenso", + "fepni", + "fepri", + "ferti", + "festi", + "fetsi", + "figre", + "filso", + "finpe", + "finti", + "firca", + "fisli", + "fizbu", + "flaci", + "flalu", + "flani", + "flecu", + "flese", + "fliba", + "flira", + "foldi", + "fonmo", + "fonxa", + "forca", + "forse", + "fraso", + "frati", + "fraxu", + "frica", + "friko", + "frili", + "frinu", + "friti", + "frumu", + "fukpi", + "fulta", + "funca", + "fusra", + "fuzme", + "gacri", + "gadri", + "galfi", + "galtu", + "galxe", + "ganlo", + "ganra", + "ganse", + "ganti", + "ganxo", + "ganzu", + "gapci", + "gapru", + "garna", + "gasnu", + "gaspo", + "gasta", + "genja", + "gento", + "genxu", + "gerku", + "gerna", + "gidva", + "gigdo", + "ginka", + "girzu", + "gismu", + "glare", + "gleki", + "gletu", + "glico", + "glife", + "glosa", + "gluta", + "gocti", + "gomsi", + "gotro", + "gradu", + "grafu", + "grake", + "grana", + "grasu", + "grava", + "greku", + "grusi", + "grute", + "gubni", + "gugde", + "gugle", + "gumri", + "gundi", + "gunka", + "gunma", + "gunro", + "gunse", + "gunta", + "gurni", + "guska", + "gusni", + "gusta", + "gutci", + "gutra", + "guzme", + "jabre", + "jadni", + "jakne", + "jalge", + "jalna", + "jalra", + "jamfu", + "jamna", + "janbe", + "janco", + "janli", + "jansu", + "janta", + "jarbu", + "jarco", + "jarki", + "jaspu", + "jatna", + "javni", + "jbama", + "jbari", + "jbena", + "jbera", + "jbini", + "jdari", + "jdice", + "jdika", + "jdima", + "jdini", + "jduli", + "jecta", + "jeftu", + "jegvo", + "jelca", + "jemna", + "jenca", + "jendu", + "jenmi", + "jensi", + "jerna", + "jersi", + "jerxo", + "jesni", + "jetce", + "jetnu", + "jgalu", + "jganu", + "jgari", + "jgena", + "jgina", + "jgira", + "jgita", + "jibni", + "jibri", + "jicla", + "jicmu", + "jijnu", + "jikca", + "jikfi", + "jikni", + "jikru", + "jilka", + "jilra", + "jimca", + "jimpe", + "jimte", + "jinci", + "jinda", + "jinga", + "jinku", + "jinme", + "jinru", + "jinsa", + "jinto", + "jinvi", + "jinzi", + "jipci", + "jipno", + "jirna", + "jisra", + "jitfa", + "jitro", + "jivbu", + "jivna", + "jmaji", + "jmifa", + "jmina", + "jmive", + "jonse", + "jordo", + "jorne", + "jubme", + "judri", + "jufra", + "jukni", + "jukpa", + "julne", + "julro", + "jundi", + "jungo", + "junla", + "junri", + "junta", + "jurme", + "jursa", + "jutsi", + "juxre", + "jvinu", + "jviso", + "kabri", + "kacma", + "kadno", + "kafke", + "kagni", + "kajde", + "kajna", + "kakne", + "kakpa", + "kalci", + "kalri", + "kalsa", + "kalte", + "kamju", + "kamni", + "kampu", + "kamre", + "kanba", + "kancu", + "kandi", + "kanji", + "kanla", + "kanpe", + "kanro", + "kansa", + "kantu", + "kanxe", + "karbi", + "karce", + "karda", + "kargu", + "karli", + "karni", + "katci", + "katna", + "kavbu", + "kazra", + "kecti", + "kekli", + "kelci", + "kelvo", + "kenka", + "kenra", + "kensa", + "kerfa", + "kerlo", + "kesri", + "ketco", + "ketsu", + "kevna", + "kibro", + "kicne", + "kijno", + "kilto", + "kinda", + "kinli", + "kisto", + "klaji", + "klaku", + "klama", + "klani", + "klesi", + "kliki", + "klina", + "kliru", + "kliti", + "klupe", + "kluza", + "kobli", + "kogno", + "kojna", + "kokso", + "kolme", + "komcu", + "konju", + "korbi", + "korcu", + "korka", + "korvo", + "kosmu", + "kosta", + "krali", + "kramu", + "krasi", + "krati", + "krefu", + "krici", + "krili", + "krinu", + "krixa", + "kruca", + "kruji", + "kruvi", + "kubli", + "kucli", + "kufra", + "kukte", + "kulnu", + "kumfa", + "kumte", + "kunra", + "kunti", + "kurfa", + "kurji", + "kurki", + "kuspe", + "kusru", + "labno", + "lacni", + "lacpu", + "lacri", + "ladru", + "lafti", + "lakne", + "lakse", + "laldo", + "lalxu", + "lamji", + "lanbi", + "lanci", + "landa", + "lanka", + "lanli", + "lanme", + "lante", + "lanxe", + "lanzu", + "larcu", + "larva", + "lasna", + "lastu", + "latmo", + "latna", + "lazni", + "lebna", + "lelxe", + "lenga", + "lenjo", + "lenku", + "lerci", + "lerfu", + "libjo", + "lidne", + "lifri", + "lijda", + "limfa", + "limna", + "lince", + "lindi", + "linga", + "linji", + "linsi", + "linto", + "lisri", + "liste", + "litce", + "litki", + "litru", + "livga", + "livla", + "logji", + "loglo", + "lojbo", + "loldi", + "lorxu", + "lubno", + "lujvo", + "luksi", + "lumci", + "lunbe", + "lunra", + "lunsa", + "luska", + "lusto", + "mabla", + "mabru", + "macnu", + "majga", + "makcu", + "makfa", + "maksi", + "malsi", + "mamta", + "manci", + "manfo", + "mango", + "manku", + "manri", + "mansa", + "manti", + "mapku", + "mapni", + "mapra", + "mapti", + "marbi", + "marce", + "marde", + "margu", + "marji", + "marna", + "marxa", + "masno", + "masti", + "matci", + "matli", + "matne", + "matra", + "mavji", + "maxri", + "mebri", + "megdo", + "mekso", + "melbi", + "meljo", + "melmi", + "menli", + "menre", + "mensi", + "mentu", + "merko", + "merli", + "metfo", + "mexno", + "midju", + "mifra", + "mikce", + "mikri", + "milti", + "milxe", + "minde", + "minji", + "minli", + "minra", + "mintu", + "mipri", + "mirli", + "misno", + "misro", + "mitre", + "mixre", + "mlana", + "mlatu", + "mleca", + "mledi", + "mluni", + "mogle", + "mokca", + "moklu", + "molki", + "molro", + "morji", + "morko", + "morna", + "morsi", + "mosra", + "mraji", + "mrilu", + "mruli", + "mucti", + "mudri", + "mugle", + "mukti", + "mulno", + "munje", + "mupli", + "murse", + "murta", + "muslo", + "mutce", + "muvdu", + "muzga", + "nabmi", + "nakni", + "nalci", + "namcu", + "nanba", + "nanca", + "nandu", + "nanla", + "nanmu", + "nanvi", + "narge", + "narju", + "natfe", + "natmi", + "natsi", + "navni", + "naxle", + "nazbi", + "nejni", + "nelci", + "nenri", + "nerde", + "nibli", + "nicfa", + "nicte", + "nikle", + "nilce", + "nimre", + "ninja", + "ninmu", + "nirna", + "nitcu", + "nivji", + "nixli", + "nobli", + "norgo", + "notci", + "nudle", + "nukni", + "nunmu", + "nupre", + "nurma", + "nusna", + "nutka", + "nutli", + "nuzba", + "nuzlo", + "pacna", + "pagbu", + "pagre", + "pajni", + "palci", + "palku", + "palma", + "palne", + "palpi", + "palta", + "pambe", + "pamga", + "panci", + "pandi", + "panje", + "panka", + "panlo", + "panpi", + "panra", + "pante", + "panzi", + "papri", + "parbi", + "pardu", + "parji", + "pastu", + "patfu", + "patlu", + "patxu", + "paznu", + "pelji", + "pelxu", + "pemci", + "penbi", + "pencu", + "pendo", + "penmi", + "pensi", + "pentu", + "perli", + "pesxu", + "petso", + "pevna", + "pezli", + "picti", + "pijne", + "pikci", + "pikta", + "pilda", + "pilji", + "pilka", + "pilno", + "pimlu", + "pinca", + "pindi", + "pinfu", + "pinji", + "pinka", + "pinsi", + "pinta", + "pinxe", + "pipno", + "pixra", + "plana", + "platu", + "pleji", + "plibu", + "plini", + "plipe", + "plise", + "plita", + "plixa", + "pluja", + "pluka", + "pluta", + "pocli", + "polje", + "polno", + "ponjo", + "ponse", + "poplu", + "porpi", + "porsi", + "porto", + "prali", + "prami", + "prane", + "preja", + "prenu", + "preri", + "preti", + "prije", + "prina", + "pritu", + "proga", + "prosa", + "pruce", + "pruni", + "pruri", + "pruxi", + "pulce", + "pulji", + "pulni", + "punji", + "punli", + "pupsu", + "purci", + "purdi", + "purmo", + "racli", + "ractu", + "radno", + "rafsi", + "ragbi", + "ragve", + "rakle", + "rakso", + "raktu", + "ralci", + "ralju", + "ralte", + "randa", + "rango", + "ranji", + "ranmi", + "ransu", + "ranti", + "ranxi", + "rapli", + "rarna", + "ratcu", + "ratni", + "rebla", + "rectu", + "rekto", + "remna", + "renro", + "renvi", + "respa", + "rexsa", + "ricfu", + "rigni", + "rijno", + "rilti", + "rimni", + "rinci", + "rindo", + "rinju", + "rinka", + "rinsa", + "rirci", + "rirni", + "rirxe", + "rismi", + "risna", + "ritli", + "rivbi", + "rokci", + "romge", + "romlo", + "ronte", + "ropno", + "rorci", + "rotsu", + "rozgu", + "ruble", + "rufsu", + "runme", + "runta", + "rupnu", + "rusko", + "rutni", + "sabji", + "sabnu", + "sacki", + "saclu", + "sadjo", + "sakci", + "sakli", + "sakta", + "salci", + "salpo", + "salri", + "salta", + "samcu", + "sampu", + "sanbu", + "sance", + "sanga", + "sanji", + "sanli", + "sanmi", + "sanso", + "santa", + "sarcu", + "sarji", + "sarlu", + "sarni", + "sarxe", + "saske", + "satci", + "satre", + "savru", + "sazri", + "sefsi", + "sefta", + "sekre", + "selci", + "selfu", + "semto", + "senci", + "sengi", + "senpi", + "senta", + "senva", + "sepli", + "serti", + "sesre", + "setca", + "sevzi", + "sfani", + "sfasa", + "sfofa", + "sfubu", + "sibli", + "siclu", + "sicni", + "sicpi", + "sidbo", + "sidju", + "sigja", + "sigma", + "sikta", + "silka", + "silna", + "simlu", + "simsa", + "simxu", + "since", + "sinma", + "sinso", + "sinxa", + "sipna", + "sirji", + "sirxo", + "sisku", + "sisti", + "sitna", + "sivni", + "skaci", + "skami", + "skapi", + "skari", + "skicu", + "skiji", + "skina", + "skori", + "skoto", + "skuba", + "skuro", + "slabu", + "slaka", + "slami", + "slanu", + "slari", + "slasi", + "sligu", + "slilu", + "sliri", + "slovo", + "sluji", + "sluni", + "smacu", + "smadi", + "smaji", + "smaka", + "smani", + "smela", + "smoka", + "smuci", + "smuni", + "smusu", + "snada", + "snanu", + "snidu", + "snime", + "snipa", + "snuji", + "snura", + "snuti", + "sobde", + "sodna", + "sodva", + "softo", + "solji", + "solri", + "sombo", + "sonci", + "sorcu", + "sorgu", + "sorni", + "sorta", + "sovda", + "spaji", + "spali", + "spano", + "spati", + "speni", + "spero", + "spisa", + "spita", + "spofu", + "spoja", + "spuda", + "sputu", + "sraji", + "sraku", + "sralo", + "srana", + "srasu", + "srera", + "srito", + "sruma", + "sruri", + "stace", + "stagi", + "staku", + "stali", + "stani", + "stapa", + "stasu", + "stati", + "steba", + "steci", + "stedu", + "stela", + "stero", + "stici", + "stidi", + "stika", + "stizu", + "stodi", + "stuna", + "stura", + "stuzi", + "sucta", + "sudga", + "sufti", + "suksa", + "sumji", + "sumne", + "sumti", + "sunga", + "sunla", + "surla", + "sutra", + "tabno", + "tabra", + "tadji", + "tadni", + "tagji", + "taksi", + "talsa", + "tamca", + "tamji", + "tamne", + "tanbo", + "tance", + "tanjo", + "tanko", + "tanru", + "tansi", + "tanxe", + "tapla", + "tarbi", + "tarci", + "tarla", + "tarmi", + "tarti", + "taske", + "tasmi", + "tasta", + "tatpi", + "tatru", + "tavla", + "taxfu", + "tcaci", + "tcadu", + "tcana", + "tcati", + "tcaxe", + "tcena", + "tcese", + "tcica", + "tcidu", + "tcika", + "tcila", + "tcima", + "tcini", + "tcita", + "temci", + "temse", + "tende", + "tenfa", + "tengu", + "terdi", + "terpa", + "terto", + "tifri", + "tigni", + "tigra", + "tikpa", + "tilju", + "tinbe", + "tinci", + "tinsa", + "tirna", + "tirse", + "tirxu", + "tisna", + "titla", + "tivni", + "tixnu", + "toknu", + "toldi", + "tonga", + "tordu", + "torni", + "torso", + "traji", + "trano", + "trati", + "trene", + "tricu", + "trina", + "trixe", + "troci", + "tsaba", + "tsali", + "tsani", + "tsapi", + "tsiju", + "tsina", + "tsuku", + "tubnu", + "tubra", + "tugni", + "tujli", + "tumla", + "tunba", + "tunka", + "tunlo", + "tunta", + "tuple", + "turko", + "turni", + "tutci", + "tutle", + "tutra", + "vacri", + "vajni", + "valsi", + "vamji", + "vamtu", + "vanbi", + "vanci", + "vanju", + "vasru", + "vasxu", + "vecnu", + "vedli", + "venfu", + "vensa", + "vente", + "vepre", + "verba", + "vibna", + "vidni", + "vidru", + "vifne", + "vikmi", + "viknu", + "vimcu", + "vindu", + "vinji", + "vinta", + "vipsi", + "virnu", + "viska", + "vitci", + "vitke", + "vitno", + "vlagi", + "vlile", + "vlina", + "vlipa", + "vofli", + "voksa", + "volve", + "vorme", + "vraga", + "vreji", + "vreta", + "vrici", + "vrude", + "vrusi", + "vubla", + "vujnu", + "vukna", + "vukro", + "xabju", + "xadba", + "xadji", + "xadni", + "xagji", + "xagri", + "xajmi", + "xaksu", + "xalbo", + "xalka", + "xalni", + "xamgu", + "xampo", + "xamsi", + "xance", + "xango", + "xanka", + "xanri", + "xansa", + "xanto", + "xarci", + "xarju", + "xarnu", + "xasli", + "xasne", + "xatra", + "xatsi", + "xazdo", + "xebni", + "xebro", + "xecto", + "xedja", + "xekri", + "xelso", + "xendo", + "xenru", + "xexso", + "xigzo", + "xindo", + "xinmo", + "xirma", + "xislu", + "xispo", + "xlali", + "xlura", + "xorbo", + "xorlo", + "xotli", + "xrabo", + "xrani", + "xriso", + "xrotu", + "xruba", + "xruki", + "xrula", + "xruti", + "xukmi", + "xulta", + "xunre", + "xurdo", + "xusra", + "xutla", + "zabna", + "zajba", + "zalvi", + "zanru", + "zarci", + "zargu", + "zasni", + "zasti", + "zbabu", + "zbani", + "zbasu", + "zbepi", + "zdani", + "zdile", + "zekri", + "zenba", + "zepti", + "zetro", + "zevla", + "zgadi", + "zgana", + "zgike", + "zifre", + "zinki", + "zirpu", + "zivle", + "zmadu", + "zmiku", + "zucna", + "zukte", + "zumri", + "zungi", + "zunle", + "zunti", + "zutse", + "zvati", + "zviki", + "jbobau", + "jbopre", + "karsna", + "cabdei", + "zunsna", + "gendra", + "glibau", + "nintadni", + "pavyseljirna", + "vlaste", + "selbri", + "latro'a", + "zdakemkulgu'a", + "mriste", + "selsku", + "fu'ivla", + "tolmo'i", + "snavei", + "xagmau", + "retsku", + "ckupau", + "skudji", + "smudra", + "prulamdei", + "vokta'a", + "tinju'i", + "jefyfa'o", + "bavlamdei", + "kinzga", + "jbocre", + "jbovla", + "xauzma", + "selkei", + "xuncku", + "spusku", + "jbogu'e", + "pampe'o", + "bripre", + "jbosnu", + "zi'evla", + "gimste", + "tolzdi", + "velski", + "samselpla", + "cnegau", + "velcki", + "selja'e", + "fasybau", + "zanfri", + "reisku", + "favgau", + "jbota'a", + "rejgau", + "malgli", + "zilkai", + "keidji", + "tersu'i", + "jbofi'e", + "cnima'o", + "mulgau", + "ningau", + "ponbau", + "mrobi'o", + "rarbau", + "zmanei", + "famyma'o", + "vacysai", + "jetmlu", + "jbonunsla", + "nunpe'i", + "fa'orma'o", + "crezenzu'e", + "jbojbe", + "cmicu'a", + "zilcmi", + "tolcando", + "zukcfu", + "depybu'i", + "mencre", + "matmau", + "nunctu", + "selma'o", + "titnanba", + "naldra", + "jvajvo", + "nunsnu", + "nerkla", + "cimjvo", + "muvgau", + "zipcpi", + "runbau", + "faumlu", + "terbri", + "balcu'e", + "dragau", + "smuvelcki", + "piksku", + "selpli", + "bregau", + "zvafa'i", + "ci'izra", + "noltruti'u", + "samtci", + "snaxa'a" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/nl.json b/coins/monero/src/wallet/seed/classic/nl.json new file mode 100644 index 00000000..b6b04567 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/nl.json @@ -0,0 +1,1628 @@ +[ + "aalglad", + "aalscholver", + "aambeeld", + "aangeef", + "aanlandig", + "aanvaard", + "aanwakker", + "aapmens", + "aarten", + "abdicatie", + "abnormaal", + "abrikoos", + "accu", + "acuut", + "adjudant", + "admiraal", + "advies", + "afbidding", + "afdracht", + "affaire", + "affiche", + "afgang", + "afkick", + "afknap", + "aflees", + "afmijner", + "afname", + "afpreekt", + "afrader", + "afspeel", + "aftocht", + "aftrek", + "afzijdig", + "ahornboom", + "aktetas", + "akzo", + "alchemist", + "alcohol", + "aldaar", + "alexander", + "alfabet", + "alfredo", + "alice", + "alikruik", + "allrisk", + "altsax", + "alufolie", + "alziend", + "amai", + "ambacht", + "ambieer", + "amina", + "amnestie", + "amok", + "ampul", + "amuzikaal", + "angela", + "aniek", + "antje", + "antwerpen", + "anya", + "aorta", + "apache", + "apekool", + "appelaar", + "arganolie", + "argeloos", + "armoede", + "arrenslee", + "artritis", + "arubaan", + "asbak", + "ascii", + "asgrauw", + "asjes", + "asml", + "aspunt", + "asurn", + "asveld", + "aterling", + "atomair", + "atrium", + "atsma", + "atypisch", + "auping", + "aura", + "avifauna", + "axiaal", + "azoriaan", + "azteek", + "azuur", + "bachelor", + "badderen", + "badhotel", + "badmantel", + "badsteden", + "balie", + "ballans", + "balvers", + "bamibal", + "banneling", + "barracuda", + "basaal", + "batelaan", + "batje", + "beambte", + "bedlamp", + "bedwelmd", + "befaamd", + "begierd", + "begraaf", + "behield", + "beijaard", + "bejaagd", + "bekaaid", + "beks", + "bektas", + "belaad", + "belboei", + "belderbos", + "beloerd", + "beluchten", + "bemiddeld", + "benadeeld", + "benijd", + "berechten", + "beroemd", + "besef", + "besseling", + "best", + "betichten", + "bevind", + "bevochten", + "bevraagd", + "bewust", + "bidplaats", + "biefstuk", + "biemans", + "biezen", + "bijbaan", + "bijeenkom", + "bijfiguur", + "bijkaart", + "bijlage", + "bijpaard", + "bijtgaar", + "bijweg", + "bimmel", + "binck", + "bint", + "biobak", + "biotisch", + "biseks", + "bistro", + "bitter", + "bitumen", + "bizar", + "blad", + "bleken", + "blender", + "bleu", + "blief", + "blijven", + "blozen", + "bock", + "boef", + "boei", + "boks", + "bolder", + "bolus", + "bolvormig", + "bomaanval", + "bombarde", + "bomma", + "bomtapijt", + "bookmaker", + "boos", + "borg", + "bosbes", + "boshuizen", + "bosloop", + "botanicus", + "bougie", + "bovag", + "boxspring", + "braad", + "brasem", + "brevet", + "brigade", + "brinckman", + "bruid", + "budget", + "buffel", + "buks", + "bulgaar", + "buma", + "butaan", + "butler", + "buuf", + "cactus", + "cafeetje", + "camcorder", + "cannabis", + "canyon", + "capoeira", + "capsule", + "carkit", + "casanova", + "catalaan", + "ceintuur", + "celdeling", + "celplasma", + "cement", + "censeren", + "ceramisch", + "cerberus", + "cerebraal", + "cesium", + "cirkel", + "citeer", + "civiel", + "claxon", + "clenbuterol", + "clicheren", + "clijsen", + "coalitie", + "coassistentschap", + "coaxiaal", + "codetaal", + "cofinanciering", + "cognac", + "coltrui", + "comfort", + "commandant", + "condensaat", + "confectie", + "conifeer", + "convector", + "copier", + "corfu", + "correct", + "coup", + "couvert", + "creatie", + "credit", + "crematie", + "cricket", + "croupier", + "cruciaal", + "cruijff", + "cuisine", + "culemborg", + "culinair", + "curve", + "cyrano", + "dactylus", + "dading", + "dagblind", + "dagje", + "daglicht", + "dagprijs", + "dagranden", + "dakdekker", + "dakpark", + "dakterras", + "dalgrond", + "dambord", + "damkat", + "damlengte", + "damman", + "danenberg", + "debbie", + "decibel", + "defect", + "deformeer", + "degelijk", + "degradant", + "dejonghe", + "dekken", + "deppen", + "derek", + "derf", + "derhalve", + "detineren", + "devalueer", + "diaken", + "dicht", + "dictaat", + "dief", + "digitaal", + "dijbreuk", + "dijkmans", + "dimbaar", + "dinsdag", + "diode", + "dirigeer", + "disbalans", + "dobermann", + "doenbaar", + "doerak", + "dogma", + "dokhaven", + "dokwerker", + "doling", + "dolphijn", + "dolven", + "dombo", + "dooraderd", + "dopeling", + "doping", + "draderig", + "drama", + "drenkbak", + "dreumes", + "drol", + "drug", + "duaal", + "dublin", + "duplicaat", + "durven", + "dusdanig", + "dutchbat", + "dutje", + "dutten", + "duur", + "duwwerk", + "dwaal", + "dweil", + "dwing", + "dyslexie", + "ecostroom", + "ecotaks", + "educatie", + "eeckhout", + "eede", + "eemland", + "eencellig", + "eeneiig", + "eenruiter", + "eenwinter", + "eerenberg", + "eerrover", + "eersel", + "eetmaal", + "efteling", + "egaal", + "egtberts", + "eickhoff", + "eidooier", + "eiland", + "eind", + "eisden", + "ekster", + "elburg", + "elevatie", + "elfkoppig", + "elfrink", + "elftal", + "elimineer", + "elleboog", + "elma", + "elodie", + "elsa", + "embleem", + "embolie", + "emoe", + "emonds", + "emplooi", + "enduro", + "enfin", + "engageer", + "entourage", + "entstof", + "epileer", + "episch", + "eppo", + "erasmus", + "erboven", + "erebaan", + "erelijst", + "ereronden", + "ereteken", + "erfhuis", + "erfwet", + "erger", + "erica", + "ermitage", + "erna", + "ernie", + "erts", + "ertussen", + "eruitzien", + "ervaar", + "erven", + "erwt", + "esbeek", + "escort", + "esdoorn", + "essing", + "etage", + "eter", + "ethanol", + "ethicus", + "etholoog", + "eufonisch", + "eurocent", + "evacuatie", + "exact", + "examen", + "executant", + "exen", + "exit", + "exogeen", + "exotherm", + "expeditie", + "expletief", + "expres", + "extase", + "extinctie", + "faal", + "faam", + "fabel", + "facultair", + "fakir", + "fakkel", + "faliekant", + "fallisch", + "famke", + "fanclub", + "fase", + "fatsoen", + "fauna", + "federaal", + "feedback", + "feest", + "feilbaar", + "feitelijk", + "felblauw", + "figurante", + "fiod", + "fitheid", + "fixeer", + "flap", + "fleece", + "fleur", + "flexibel", + "flits", + "flos", + "flow", + "fluweel", + "foezelen", + "fokkelman", + "fokpaard", + "fokvee", + "folder", + "follikel", + "folmer", + "folteraar", + "fooi", + "foolen", + "forfait", + "forint", + "formule", + "fornuis", + "fosfaat", + "foxtrot", + "foyer", + "fragiel", + "frater", + "freak", + "freddie", + "fregat", + "freon", + "frijnen", + "fructose", + "frunniken", + "fuiven", + "funshop", + "furieus", + "fysica", + "gadget", + "galder", + "galei", + "galg", + "galvlieg", + "galzuur", + "ganesh", + "gaswet", + "gaza", + "gazelle", + "geaaid", + "gebiecht", + "gebufferd", + "gedijd", + "geef", + "geflanst", + "gefreesd", + "gegaan", + "gegijzeld", + "gegniffel", + "gegraaid", + "gehikt", + "gehobbeld", + "gehucht", + "geiser", + "geiten", + "gekaakt", + "gekheid", + "gekijf", + "gekmakend", + "gekocht", + "gekskap", + "gekte", + "gelubberd", + "gemiddeld", + "geordend", + "gepoederd", + "gepuft", + "gerda", + "gerijpt", + "geseald", + "geshockt", + "gesierd", + "geslaagd", + "gesnaaid", + "getracht", + "getwijfel", + "geuit", + "gevecht", + "gevlagd", + "gewicht", + "gezaagd", + "gezocht", + "ghanees", + "giebelen", + "giechel", + "giepmans", + "gips", + "giraal", + "gistachtig", + "gitaar", + "glaasje", + "gletsjer", + "gleuf", + "glibberen", + "glijbaan", + "gloren", + "gluipen", + "gluren", + "gluur", + "gnoe", + "goddelijk", + "godgans", + "godschalk", + "godzalig", + "goeierd", + "gogme", + "goklustig", + "gokwereld", + "gonggrijp", + "gonje", + "goor", + "grabbel", + "graf", + "graveer", + "grif", + "grolleman", + "grom", + "groosman", + "grubben", + "gruijs", + "grut", + "guacamole", + "guido", + "guppy", + "haazen", + "hachelijk", + "haex", + "haiku", + "hakhout", + "hakken", + "hanegem", + "hans", + "hanteer", + "harrie", + "hazebroek", + "hedonist", + "heil", + "heineken", + "hekhuis", + "hekman", + "helbig", + "helga", + "helwegen", + "hengelaar", + "herkansen", + "hermafrodiet", + "hertaald", + "hiaat", + "hikspoors", + "hitachi", + "hitparade", + "hobo", + "hoeve", + "holocaust", + "hond", + "honnepon", + "hoogacht", + "hotelbed", + "hufter", + "hugo", + "huilbier", + "hulk", + "humus", + "huwbaar", + "huwelijk", + "hype", + "iconisch", + "idema", + "ideogram", + "idolaat", + "ietje", + "ijker", + "ijkheid", + "ijklijn", + "ijkmaat", + "ijkwezen", + "ijmuiden", + "ijsbox", + "ijsdag", + "ijselijk", + "ijskoud", + "ilse", + "immuun", + "impliceer", + "impuls", + "inbijten", + "inbuigen", + "indijken", + "induceer", + "indy", + "infecteer", + "inhaak", + "inkijk", + "inluiden", + "inmijnen", + "inoefenen", + "inpolder", + "inrijden", + "inslaan", + "invitatie", + "inwaaien", + "ionisch", + "isaac", + "isolatie", + "isotherm", + "isra", + "italiaan", + "ivoor", + "jacobs", + "jakob", + "jammen", + "jampot", + "jarig", + "jehova", + "jenever", + "jezus", + "joana", + "jobdienst", + "josua", + "joule", + "juich", + "jurk", + "juut", + "kaas", + "kabelaar", + "kabinet", + "kagenaar", + "kajuit", + "kalebas", + "kalm", + "kanjer", + "kapucijn", + "karregat", + "kart", + "katvanger", + "katwijk", + "kegelaar", + "keiachtig", + "keizer", + "kenletter", + "kerdijk", + "keus", + "kevlar", + "kezen", + "kickback", + "kieviet", + "kijken", + "kikvors", + "kilheid", + "kilobit", + "kilsdonk", + "kipschnitzel", + "kissebis", + "klad", + "klagelijk", + "klak", + "klapbaar", + "klaver", + "klene", + "klets", + "klijnhout", + "klit", + "klok", + "klonen", + "klotefilm", + "kluif", + "klumper", + "klus", + "knabbel", + "knagen", + "knaven", + "kneedbaar", + "knmi", + "knul", + "knus", + "kokhals", + "komiek", + "komkommer", + "kompaan", + "komrij", + "komvormig", + "koning", + "kopbal", + "kopklep", + "kopnagel", + "koppejan", + "koptekst", + "kopwand", + "koraal", + "kosmisch", + "kostbaar", + "kram", + "kraneveld", + "kras", + "kreling", + "krengen", + "kribbe", + "krik", + "kruid", + "krulbol", + "kuijper", + "kuipbank", + "kuit", + "kuiven", + "kutsmoes", + "kuub", + "kwak", + "kwatong", + "kwetsbaar", + "kwezelaar", + "kwijnen", + "kwik", + "kwinkslag", + "kwitantie", + "lading", + "lakbeits", + "lakken", + "laklaag", + "lakmoes", + "lakwijk", + "lamheid", + "lamp", + "lamsbout", + "lapmiddel", + "larve", + "laser", + "latijn", + "latuw", + "lawaai", + "laxeerpil", + "lebberen", + "ledeboer", + "leefbaar", + "leeman", + "lefdoekje", + "lefhebber", + "legboor", + "legsel", + "leguaan", + "leiplaat", + "lekdicht", + "lekrijden", + "leksteen", + "lenen", + "leraar", + "lesbienne", + "leugenaar", + "leut", + "lexicaal", + "lezing", + "lieten", + "liggeld", + "lijdzaam", + "lijk", + "lijmstang", + "lijnschip", + "likdoorn", + "likken", + "liksteen", + "limburg", + "link", + "linoleum", + "lipbloem", + "lipman", + "lispelen", + "lissabon", + "litanie", + "liturgie", + "lochem", + "loempia", + "loesje", + "logheid", + "lonen", + "lonneke", + "loom", + "loos", + "losbaar", + "loslaten", + "losplaats", + "loting", + "lotnummer", + "lots", + "louie", + "lourdes", + "louter", + "lowbudget", + "luijten", + "luikenaar", + "luilak", + "luipaard", + "luizenbos", + "lulkoek", + "lumen", + "lunzen", + "lurven", + "lutjeboer", + "luttel", + "lutz", + "luuk", + "luwte", + "luyendijk", + "lyceum", + "lynx", + "maakbaar", + "magdalena", + "malheid", + "manchet", + "manfred", + "manhaftig", + "mank", + "mantel", + "marion", + "marxist", + "masmeijer", + "massaal", + "matsen", + "matverf", + "matze", + "maude", + "mayonaise", + "mechanica", + "meifeest", + "melodie", + "meppelink", + "midvoor", + "midweeks", + "midzomer", + "miezel", + "mijnraad", + "minus", + "mirck", + "mirte", + "mispakken", + "misraden", + "miswassen", + "mitella", + "moker", + "molecule", + "mombakkes", + "moonen", + "mopperaar", + "moraal", + "morgana", + "mormel", + "mosselaar", + "motregen", + "mouw", + "mufheid", + "mutueel", + "muzelman", + "naaidoos", + "naald", + "nadeel", + "nadruk", + "nagy", + "nahon", + "naima", + "nairobi", + "napalm", + "napels", + "napijn", + "napoleon", + "narigheid", + "narratief", + "naseizoen", + "nasibal", + "navigatie", + "nawijn", + "negatief", + "nekletsel", + "nekwervel", + "neolatijn", + "neonataal", + "neptunus", + "nerd", + "nest", + "neuzelaar", + "nihiliste", + "nijenhuis", + "nijging", + "nijhoff", + "nijl", + "nijptang", + "nippel", + "nokkenas", + "noordam", + "noren", + "normaal", + "nottelman", + "notulant", + "nout", + "nuance", + "nuchter", + "nudorp", + "nulde", + "nullijn", + "nulmeting", + "nunspeet", + "nylon", + "obelisk", + "object", + "oblie", + "obsceen", + "occlusie", + "oceaan", + "ochtend", + "ockhuizen", + "oerdom", + "oergezond", + "oerlaag", + "oester", + "okhuijsen", + "olifant", + "olijfboer", + "omaans", + "ombudsman", + "omdat", + "omdijken", + "omdoen", + "omgebouwd", + "omkeer", + "omkomen", + "ommegaand", + "ommuren", + "omroep", + "omruil", + "omslaan", + "omsmeden", + "omvaar", + "onaardig", + "onedel", + "onenig", + "onheilig", + "onrecht", + "onroerend", + "ontcijfer", + "onthaal", + "ontvallen", + "ontzadeld", + "onzacht", + "onzin", + "onzuiver", + "oogappel", + "ooibos", + "ooievaar", + "ooit", + "oorarts", + "oorhanger", + "oorijzer", + "oorklep", + "oorschelp", + "oorworm", + "oorzaak", + "opdagen", + "opdien", + "opdweilen", + "opel", + "opgebaard", + "opinie", + "opjutten", + "opkijken", + "opklaar", + "opkuisen", + "opkwam", + "opnaaien", + "opossum", + "opsieren", + "opsmeer", + "optreden", + "opvijzel", + "opvlammen", + "opwind", + "oraal", + "orchidee", + "orkest", + "ossuarium", + "ostendorf", + "oublie", + "oudachtig", + "oudbakken", + "oudnoors", + "oudshoorn", + "oudtante", + "oven", + "over", + "oxidant", + "pablo", + "pacht", + "paktafel", + "pakzadel", + "paljas", + "panharing", + "papfles", + "paprika", + "parochie", + "paus", + "pauze", + "paviljoen", + "peek", + "pegel", + "peigeren", + "pekela", + "pendant", + "penibel", + "pepmiddel", + "peptalk", + "periferie", + "perron", + "pessarium", + "peter", + "petfles", + "petgat", + "peuk", + "pfeifer", + "picknick", + "pief", + "pieneman", + "pijlkruid", + "pijnacker", + "pijpelink", + "pikdonker", + "pikeer", + "pilaar", + "pionier", + "pipet", + "piscine", + "pissebed", + "pitchen", + "pixel", + "plamuren", + "plan", + "plausibel", + "plegen", + "plempen", + "pleonasme", + "plezant", + "podoloog", + "pofmouw", + "pokdalig", + "ponywagen", + "popachtig", + "popidool", + "porren", + "positie", + "potten", + "pralen", + "prezen", + "prijzen", + "privaat", + "proef", + "prooi", + "prozawerk", + "pruik", + "prul", + "publiceer", + "puck", + "puilen", + "pukkelig", + "pulveren", + "pupil", + "puppy", + "purmerend", + "pustjens", + "putemmer", + "puzzelaar", + "queenie", + "quiche", + "raam", + "raar", + "raat", + "raes", + "ralf", + "rally", + "ramona", + "ramselaar", + "ranonkel", + "rapen", + "rapunzel", + "rarekiek", + "rarigheid", + "rattenhol", + "ravage", + "reactie", + "recreant", + "redacteur", + "redster", + "reewild", + "regie", + "reijnders", + "rein", + "replica", + "revanche", + "rigide", + "rijbaan", + "rijdansen", + "rijgen", + "rijkdom", + "rijles", + "rijnwijn", + "rijpma", + "rijstafel", + "rijtaak", + "rijzwepen", + "rioleer", + "ripdeal", + "riphagen", + "riskant", + "rits", + "rivaal", + "robbedoes", + "robot", + "rockact", + "rodijk", + "rogier", + "rohypnol", + "rollaag", + "rolpaal", + "roltafel", + "roof", + "roon", + "roppen", + "rosbief", + "rosharig", + "rosielle", + "rotan", + "rotleven", + "rotten", + "rotvaart", + "royaal", + "royeer", + "rubato", + "ruby", + "ruche", + "rudge", + "ruggetje", + "rugnummer", + "rugpijn", + "rugtitel", + "rugzak", + "ruilbaar", + "ruis", + "ruit", + "rukwind", + "rulijs", + "rumoeren", + "rumsdorp", + "rumtaart", + "runnen", + "russchen", + "ruwkruid", + "saboteer", + "saksisch", + "salade", + "salpeter", + "sambabal", + "samsam", + "satelliet", + "satineer", + "saus", + "scampi", + "scarabee", + "scenario", + "schobben", + "schubben", + "scout", + "secessie", + "secondair", + "seculair", + "sediment", + "seeland", + "settelen", + "setwinst", + "sheriff", + "shiatsu", + "siciliaan", + "sidderaal", + "sigma", + "sijben", + "silvana", + "simkaart", + "sinds", + "situatie", + "sjaak", + "sjardijn", + "sjezen", + "sjor", + "skinhead", + "skylab", + "slamixen", + "sleijpen", + "slijkerig", + "slordig", + "slowaak", + "sluieren", + "smadelijk", + "smiecht", + "smoel", + "smos", + "smukken", + "snackcar", + "snavel", + "sneaker", + "sneu", + "snijdbaar", + "snit", + "snorder", + "soapbox", + "soetekouw", + "soigneren", + "sojaboon", + "solo", + "solvabel", + "somber", + "sommatie", + "soort", + "soppen", + "sopraan", + "soundbar", + "spanen", + "spawater", + "spijgat", + "spinaal", + "spionage", + "spiraal", + "spleet", + "splijt", + "spoed", + "sporen", + "spul", + "spuug", + "spuw", + "stalen", + "standaard", + "star", + "stefan", + "stencil", + "stijf", + "stil", + "stip", + "stopdas", + "stoten", + "stoven", + "straat", + "strobbe", + "strubbel", + "stucadoor", + "stuif", + "stukadoor", + "subhoofd", + "subregent", + "sudoku", + "sukade", + "sulfaat", + "surinaams", + "suus", + "syfilis", + "symboliek", + "sympathie", + "synagoge", + "synchroon", + "synergie", + "systeem", + "taanderij", + "tabak", + "tachtig", + "tackelen", + "taiwanees", + "talman", + "tamheid", + "tangaslip", + "taps", + "tarkan", + "tarwe", + "tasman", + "tatjana", + "taxameter", + "teil", + "teisman", + "telbaar", + "telco", + "telganger", + "telstar", + "tenant", + "tepel", + "terzet", + "testament", + "ticket", + "tiesinga", + "tijdelijk", + "tika", + "tiksel", + "tilleman", + "timbaal", + "tinsteen", + "tiplijn", + "tippelaar", + "tjirpen", + "toezeggen", + "tolbaas", + "tolgeld", + "tolhek", + "tolo", + "tolpoort", + "toltarief", + "tolvrij", + "tomaat", + "tondeuse", + "toog", + "tooi", + "toonbaar", + "toos", + "topclub", + "toppen", + "toptalent", + "topvrouw", + "toque", + "torment", + "tornado", + "tosti", + "totdat", + "toucheer", + "toulouse", + "tournedos", + "tout", + "trabant", + "tragedie", + "trailer", + "traject", + "traktaat", + "trauma", + "tray", + "trechter", + "tred", + "tref", + "treur", + "troebel", + "tros", + "trucage", + "truffel", + "tsaar", + "tucht", + "tuenter", + "tuitelig", + "tukje", + "tuktuk", + "tulp", + "tuma", + "tureluurs", + "twijfel", + "twitteren", + "tyfoon", + "typograaf", + "ugandees", + "uiachtig", + "uier", + "uisnipper", + "ultiem", + "unitair", + "uranium", + "urbaan", + "urendag", + "ursula", + "uurcirkel", + "uurglas", + "uzelf", + "vaat", + "vakantie", + "vakleraar", + "valbijl", + "valpartij", + "valreep", + "valuatie", + "vanmiddag", + "vanonder", + "varaan", + "varken", + "vaten", + "veenbes", + "veeteler", + "velgrem", + "vellekoop", + "velvet", + "veneberg", + "venlo", + "vent", + "venusberg", + "venw", + "veredeld", + "verf", + "verhaaf", + "vermaak", + "vernaaid", + "verraad", + "vers", + "veruit", + "verzaagd", + "vetachtig", + "vetlok", + "vetmesten", + "veto", + "vetrek", + "vetstaart", + "vetten", + "veurink", + "viaduct", + "vibrafoon", + "vicariaat", + "vieux", + "vieveen", + "vijfvoud", + "villa", + "vilt", + "vimmetje", + "vindbaar", + "vips", + "virtueel", + "visdieven", + "visee", + "visie", + "vlaag", + "vleugel", + "vmbo", + "vocht", + "voesenek", + "voicemail", + "voip", + "volg", + "vork", + "vorselaar", + "voyeur", + "vracht", + "vrekkig", + "vreten", + "vrije", + "vrozen", + "vrucht", + "vucht", + "vugt", + "vulkaan", + "vulmiddel", + "vulva", + "vuren", + "waas", + "wacht", + "wadvogel", + "wafel", + "waffel", + "walhalla", + "walnoot", + "walraven", + "wals", + "walvis", + "wandaad", + "wanen", + "wanmolen", + "want", + "warklomp", + "warm", + "wasachtig", + "wasteil", + "watt", + "webhandel", + "weblog", + "webpagina", + "webzine", + "wedereis", + "wedstrijd", + "weeda", + "weert", + "wegmaaien", + "wegscheer", + "wekelijks", + "wekken", + "wekroep", + "wektoon", + "weldaad", + "welwater", + "wendbaar", + "wenkbrauw", + "wens", + "wentelaar", + "wervel", + "wesseling", + "wetboek", + "wetmatig", + "whirlpool", + "wijbrands", + "wijdbeens", + "wijk", + "wijnbes", + "wijting", + "wild", + "wimpelen", + "wingebied", + "winplaats", + "winter", + "winzucht", + "wipstaart", + "wisgerhof", + "withaar", + "witmaker", + "wokkel", + "wolf", + "wonenden", + "woning", + "worden", + "worp", + "wortel", + "wrat", + "wrijf", + "wringen", + "yoghurt", + "ypsilon", + "zaaijer", + "zaak", + "zacharias", + "zakelijk", + "zakkam", + "zakwater", + "zalf", + "zalig", + "zaniken", + "zebracode", + "zeeblauw", + "zeef", + "zeegaand", + "zeeuw", + "zege", + "zegje", + "zeil", + "zesbaans", + "zesenhalf", + "zeskantig", + "zesmaal", + "zetbaas", + "zetpil", + "zeulen", + "ziezo", + "zigzag", + "zijaltaar", + "zijbeuk", + "zijlijn", + "zijmuur", + "zijn", + "zijwaarts", + "zijzelf", + "zilt", + "zimmerman", + "zinledig", + "zinnelijk", + "zionist", + "zitdag", + "zitruimte", + "zitzak", + "zoal", + "zodoende", + "zoekbots", + "zoem", + "zoiets", + "zojuist", + "zondaar", + "zotskap", + "zottebol", + "zucht", + "zuivel", + "zulk", + "zult", + "zuster", + "zuur", + "zweedijk", + "zwendel", + "zwepen", + "zwiep", + "zwijmel", + "zworen" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/pt.json b/coins/monero/src/wallet/seed/classic/pt.json new file mode 100644 index 00000000..4d1fbac5 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/pt.json @@ -0,0 +1,1628 @@ +[ + "abaular", + "abdominal", + "abeto", + "abissinio", + "abjeto", + "ablucao", + "abnegar", + "abotoar", + "abrutalhar", + "absurdo", + "abutre", + "acautelar", + "accessorios", + "acetona", + "achocolatado", + "acirrar", + "acne", + "acovardar", + "acrostico", + "actinomicete", + "acustico", + "adaptavel", + "adeus", + "adivinho", + "adjunto", + "admoestar", + "adnominal", + "adotivo", + "adquirir", + "adriatico", + "adsorcao", + "adutora", + "advogar", + "aerossol", + "afazeres", + "afetuoso", + "afixo", + "afluir", + "afortunar", + "afrouxar", + "aftosa", + "afunilar", + "agentes", + "agito", + "aglutinar", + "aiatola", + "aimore", + "aino", + "aipo", + "airoso", + "ajeitar", + "ajoelhar", + "ajudante", + "ajuste", + "alazao", + "albumina", + "alcunha", + "alegria", + "alexandre", + "alforriar", + "alguns", + "alhures", + "alivio", + "almoxarife", + "alotropico", + "alpiste", + "alquimista", + "alsaciano", + "altura", + "aluviao", + "alvura", + "amazonico", + "ambulatorio", + "ametodico", + "amizades", + "amniotico", + "amovivel", + "amurada", + "anatomico", + "ancorar", + "anexo", + "anfora", + "aniversario", + "anjo", + "anotar", + "ansioso", + "anturio", + "anuviar", + "anverso", + "anzol", + "aonde", + "apaziguar", + "apito", + "aplicavel", + "apoteotico", + "aprimorar", + "aprumo", + "apto", + "apuros", + "aquoso", + "arauto", + "arbusto", + "arduo", + "aresta", + "arfar", + "arguto", + "aritmetico", + "arlequim", + "armisticio", + "aromatizar", + "arpoar", + "arquivo", + "arrumar", + "arsenio", + "arturiano", + "aruaque", + "arvores", + "asbesto", + "ascorbico", + "aspirina", + "asqueroso", + "assustar", + "astuto", + "atazanar", + "ativo", + "atletismo", + "atmosferico", + "atormentar", + "atroz", + "aturdir", + "audivel", + "auferir", + "augusto", + "aula", + "aumento", + "aurora", + "autuar", + "avatar", + "avexar", + "avizinhar", + "avolumar", + "avulso", + "axiomatico", + "azerbaijano", + "azimute", + "azoto", + "azulejo", + "bacteriologista", + "badulaque", + "baforada", + "baixote", + "bajular", + "balzaquiana", + "bambuzal", + "banzo", + "baoba", + "baqueta", + "barulho", + "bastonete", + "batuta", + "bauxita", + "bavaro", + "bazuca", + "bcrepuscular", + "beato", + "beduino", + "begonia", + "behaviorista", + "beisebol", + "belzebu", + "bemol", + "benzido", + "beocio", + "bequer", + "berro", + "besuntar", + "betume", + "bexiga", + "bezerro", + "biatlon", + "biboca", + "bicuspide", + "bidirecional", + "bienio", + "bifurcar", + "bigorna", + "bijuteria", + "bimotor", + "binormal", + "bioxido", + "bipolarizacao", + "biquini", + "birutice", + "bisturi", + "bituca", + "biunivoco", + "bivalve", + "bizarro", + "blasfemo", + "blenorreia", + "blindar", + "bloqueio", + "blusao", + "boazuda", + "bofete", + "bojudo", + "bolso", + "bombordo", + "bonzo", + "botina", + "boquiaberto", + "bostoniano", + "botulismo", + "bourbon", + "bovino", + "boximane", + "bravura", + "brevidade", + "britar", + "broxar", + "bruno", + "bruxuleio", + "bubonico", + "bucolico", + "buda", + "budista", + "bueiro", + "buffer", + "bugre", + "bujao", + "bumerangue", + "burundines", + "busto", + "butique", + "buzios", + "caatinga", + "cabuqui", + "cacunda", + "cafuzo", + "cajueiro", + "camurca", + "canudo", + "caquizeiro", + "carvoeiro", + "casulo", + "catuaba", + "cauterizar", + "cebolinha", + "cedula", + "ceifeiro", + "celulose", + "cerzir", + "cesto", + "cetro", + "ceus", + "cevar", + "chavena", + "cheroqui", + "chita", + "chovido", + "chuvoso", + "ciatico", + "cibernetico", + "cicuta", + "cidreira", + "cientistas", + "cifrar", + "cigarro", + "cilio", + "cimo", + "cinzento", + "cioso", + "cipriota", + "cirurgico", + "cisto", + "citrico", + "ciumento", + "civismo", + "clavicula", + "clero", + "clitoris", + "cluster", + "coaxial", + "cobrir", + "cocota", + "codorniz", + "coexistir", + "cogumelo", + "coito", + "colusao", + "compaixao", + "comutativo", + "contentamento", + "convulsivo", + "coordenativa", + "coquetel", + "correto", + "corvo", + "costureiro", + "cotovia", + "covil", + "cozinheiro", + "cretino", + "cristo", + "crivo", + "crotalo", + "cruzes", + "cubo", + "cucuia", + "cueiro", + "cuidar", + "cujo", + "cultural", + "cunilingua", + "cupula", + "curvo", + "custoso", + "cutucar", + "czarismo", + "dablio", + "dacota", + "dados", + "daguerreotipo", + "daiquiri", + "daltonismo", + "damista", + "dantesco", + "daquilo", + "darwinista", + "dasein", + "dativo", + "deao", + "debutantes", + "decurso", + "deduzir", + "defunto", + "degustar", + "dejeto", + "deltoide", + "demover", + "denunciar", + "deputado", + "deque", + "dervixe", + "desvirtuar", + "deturpar", + "deuteronomio", + "devoto", + "dextrose", + "dezoito", + "diatribe", + "dicotomico", + "didatico", + "dietista", + "difuso", + "digressao", + "diluvio", + "diminuto", + "dinheiro", + "dinossauro", + "dioxido", + "diplomatico", + "dique", + "dirimivel", + "disturbio", + "diurno", + "divulgar", + "dizivel", + "doar", + "dobro", + "docura", + "dodoi", + "doer", + "dogue", + "doloso", + "domo", + "donzela", + "doping", + "dorsal", + "dossie", + "dote", + "doutro", + "doze", + "dravidico", + "dreno", + "driver", + "dropes", + "druso", + "dubnio", + "ducto", + "dueto", + "dulija", + "dundum", + "duodeno", + "duquesa", + "durou", + "duvidoso", + "duzia", + "ebano", + "ebrio", + "eburneo", + "echarpe", + "eclusa", + "ecossistema", + "ectoplasma", + "ecumenismo", + "eczema", + "eden", + "editorial", + "edredom", + "edulcorar", + "efetuar", + "efigie", + "efluvio", + "egiptologo", + "egresso", + "egua", + "einsteiniano", + "eira", + "eivar", + "eixos", + "ejetar", + "elastomero", + "eldorado", + "elixir", + "elmo", + "eloquente", + "elucidativo", + "emaranhar", + "embutir", + "emerito", + "emfa", + "emitir", + "emotivo", + "empuxo", + "emulsao", + "enamorar", + "encurvar", + "enduro", + "enevoar", + "enfurnar", + "enguico", + "enho", + "enigmista", + "enlutar", + "enormidade", + "enpreendimento", + "enquanto", + "enriquecer", + "enrugar", + "entusiastico", + "enunciar", + "envolvimento", + "enxuto", + "enzimatico", + "eolico", + "epiteto", + "epoxi", + "epura", + "equivoco", + "erario", + "erbio", + "ereto", + "erguido", + "erisipela", + "ermo", + "erotizar", + "erros", + "erupcao", + "ervilha", + "esburacar", + "escutar", + "esfuziante", + "esguio", + "esloveno", + "esmurrar", + "esoterismo", + "esperanca", + "espirito", + "espurio", + "essencialmente", + "esturricar", + "esvoacar", + "etario", + "eterno", + "etiquetar", + "etnologo", + "etos", + "etrusco", + "euclidiano", + "euforico", + "eugenico", + "eunuco", + "europio", + "eustaquio", + "eutanasia", + "evasivo", + "eventualidade", + "evitavel", + "evoluir", + "exaustor", + "excursionista", + "exercito", + "exfoliado", + "exito", + "exotico", + "expurgo", + "exsudar", + "extrusora", + "exumar", + "fabuloso", + "facultativo", + "fado", + "fagulha", + "faixas", + "fajuto", + "faltoso", + "famoso", + "fanzine", + "fapesp", + "faquir", + "fartura", + "fastio", + "faturista", + "fausto", + "favorito", + "faxineira", + "fazer", + "fealdade", + "febril", + "fecundo", + "fedorento", + "feerico", + "feixe", + "felicidade", + "felpudo", + "feltro", + "femur", + "fenotipo", + "fervura", + "festivo", + "feto", + "feudo", + "fevereiro", + "fezinha", + "fiasco", + "fibra", + "ficticio", + "fiduciario", + "fiesp", + "fifa", + "figurino", + "fijiano", + "filtro", + "finura", + "fiorde", + "fiquei", + "firula", + "fissurar", + "fitoteca", + "fivela", + "fixo", + "flavio", + "flexor", + "flibusteiro", + "flotilha", + "fluxograma", + "fobos", + "foco", + "fofura", + "foguista", + "foie", + "foliculo", + "fominha", + "fonte", + "forum", + "fosso", + "fotossintese", + "foxtrote", + "fraudulento", + "frevo", + "frivolo", + "frouxo", + "frutose", + "fuba", + "fucsia", + "fugitivo", + "fuinha", + "fujao", + "fulustreco", + "fumo", + "funileiro", + "furunculo", + "fustigar", + "futurologo", + "fuxico", + "fuzue", + "gabriel", + "gado", + "gaelico", + "gafieira", + "gaguejo", + "gaivota", + "gajo", + "galvanoplastico", + "gamo", + "ganso", + "garrucha", + "gastronomo", + "gatuno", + "gaussiano", + "gaviao", + "gaxeta", + "gazeteiro", + "gear", + "geiser", + "geminiano", + "generoso", + "genuino", + "geossinclinal", + "gerundio", + "gestual", + "getulista", + "gibi", + "gigolo", + "gilete", + "ginseng", + "giroscopio", + "glaucio", + "glacial", + "gleba", + "glifo", + "glote", + "glutonia", + "gnostico", + "goela", + "gogo", + "goitaca", + "golpista", + "gomo", + "gonzo", + "gorro", + "gostou", + "goticula", + "gourmet", + "governo", + "gozo", + "graxo", + "grevista", + "grito", + "grotesco", + "gruta", + "guaxinim", + "gude", + "gueto", + "guizo", + "guloso", + "gume", + "guru", + "gustativo", + "grelhado", + "gutural", + "habitue", + "haitiano", + "halterofilista", + "hamburguer", + "hanseniase", + "happening", + "harpista", + "hastear", + "haveres", + "hebreu", + "hectometro", + "hedonista", + "hegira", + "helena", + "helminto", + "hemorroidas", + "henrique", + "heptassilabo", + "hertziano", + "hesitar", + "heterossexual", + "heuristico", + "hexagono", + "hiato", + "hibrido", + "hidrostatico", + "hieroglifo", + "hifenizar", + "higienizar", + "hilario", + "himen", + "hino", + "hippie", + "hirsuto", + "historiografia", + "hitlerista", + "hodometro", + "hoje", + "holograma", + "homus", + "honroso", + "hoquei", + "horto", + "hostilizar", + "hotentote", + "huguenote", + "humilde", + "huno", + "hurra", + "hutu", + "iaia", + "ialorixa", + "iambico", + "iansa", + "iaque", + "iara", + "iatista", + "iberico", + "ibis", + "icar", + "iceberg", + "icosagono", + "idade", + "ideologo", + "idiotice", + "idoso", + "iemenita", + "iene", + "igarape", + "iglu", + "ignorar", + "igreja", + "iguaria", + "iidiche", + "ilativo", + "iletrado", + "ilharga", + "ilimitado", + "ilogismo", + "ilustrissimo", + "imaturo", + "imbuzeiro", + "imerso", + "imitavel", + "imovel", + "imputar", + "imutavel", + "inaveriguavel", + "incutir", + "induzir", + "inextricavel", + "infusao", + "ingua", + "inhame", + "iniquo", + "injusto", + "inning", + "inoxidavel", + "inquisitorial", + "insustentavel", + "intumescimento", + "inutilizavel", + "invulneravel", + "inzoneiro", + "iodo", + "iogurte", + "ioio", + "ionosfera", + "ioruba", + "iota", + "ipsilon", + "irascivel", + "iris", + "irlandes", + "irmaos", + "iroques", + "irrupcao", + "isca", + "isento", + "islandes", + "isotopo", + "isqueiro", + "israelita", + "isso", + "isto", + "iterbio", + "itinerario", + "itrio", + "iuane", + "iugoslavo", + "jabuticabeira", + "jacutinga", + "jade", + "jagunco", + "jainista", + "jaleco", + "jambo", + "jantarada", + "japones", + "jaqueta", + "jarro", + "jasmim", + "jato", + "jaula", + "javel", + "jazz", + "jegue", + "jeitoso", + "jejum", + "jenipapo", + "jeova", + "jequitiba", + "jersei", + "jesus", + "jetom", + "jiboia", + "jihad", + "jilo", + "jingle", + "jipe", + "jocoso", + "joelho", + "joguete", + "joio", + "jojoba", + "jorro", + "jota", + "joule", + "joviano", + "jubiloso", + "judoca", + "jugular", + "juizo", + "jujuba", + "juliano", + "jumento", + "junto", + "jururu", + "justo", + "juta", + "juventude", + "labutar", + "laguna", + "laico", + "lajota", + "lanterninha", + "lapso", + "laquear", + "lastro", + "lauto", + "lavrar", + "laxativo", + "lazer", + "leasing", + "lebre", + "lecionar", + "ledo", + "leguminoso", + "leitura", + "lele", + "lemure", + "lento", + "leonardo", + "leopardo", + "lepton", + "leque", + "leste", + "letreiro", + "leucocito", + "levitico", + "lexicologo", + "lhama", + "lhufas", + "liame", + "licoroso", + "lidocaina", + "liliputiano", + "limusine", + "linotipo", + "lipoproteina", + "liquidos", + "lirismo", + "lisura", + "liturgico", + "livros", + "lixo", + "lobulo", + "locutor", + "lodo", + "logro", + "lojista", + "lombriga", + "lontra", + "loop", + "loquaz", + "lorota", + "losango", + "lotus", + "louvor", + "luar", + "lubrificavel", + "lucros", + "lugubre", + "luis", + "luminoso", + "luneta", + "lustroso", + "luto", + "luvas", + "luxuriante", + "luzeiro", + "maduro", + "maestro", + "mafioso", + "magro", + "maiuscula", + "majoritario", + "malvisto", + "mamute", + "manutencao", + "mapoteca", + "maquinista", + "marzipa", + "masturbar", + "matuto", + "mausoleu", + "mavioso", + "maxixe", + "mazurca", + "meandro", + "mecha", + "medusa", + "mefistofelico", + "megera", + "meirinho", + "melro", + "memorizar", + "menu", + "mequetrefe", + "mertiolate", + "mestria", + "metroviario", + "mexilhao", + "mezanino", + "miau", + "microssegundo", + "midia", + "migratorio", + "mimosa", + "minuto", + "miosotis", + "mirtilo", + "misturar", + "mitzvah", + "miudos", + "mixuruca", + "mnemonico", + "moagem", + "mobilizar", + "modulo", + "moer", + "mofo", + "mogno", + "moita", + "molusco", + "monumento", + "moqueca", + "morubixaba", + "mostruario", + "motriz", + "mouse", + "movivel", + "mozarela", + "muarra", + "muculmano", + "mudo", + "mugir", + "muitos", + "mumunha", + "munir", + "muon", + "muquira", + "murros", + "musselina", + "nacoes", + "nado", + "naftalina", + "nago", + "naipe", + "naja", + "nalgum", + "namoro", + "nanquim", + "napolitano", + "naquilo", + "nascimento", + "nautilo", + "navios", + "nazista", + "nebuloso", + "nectarina", + "nefrologo", + "negus", + "nelore", + "nenufar", + "nepotismo", + "nervura", + "neste", + "netuno", + "neutron", + "nevoeiro", + "newtoniano", + "nexo", + "nhenhenhem", + "nhoque", + "nigeriano", + "niilista", + "ninho", + "niobio", + "niponico", + "niquelar", + "nirvana", + "nisto", + "nitroglicerina", + "nivoso", + "nobreza", + "nocivo", + "noel", + "nogueira", + "noivo", + "nojo", + "nominativo", + "nonuplo", + "noruegues", + "nostalgico", + "noturno", + "nouveau", + "nuanca", + "nublar", + "nucleotideo", + "nudista", + "nulo", + "numismatico", + "nunquinha", + "nupcias", + "nutritivo", + "nuvens", + "oasis", + "obcecar", + "obeso", + "obituario", + "objetos", + "oblongo", + "obnoxio", + "obrigatorio", + "obstruir", + "obtuso", + "obus", + "obvio", + "ocaso", + "occipital", + "oceanografo", + "ocioso", + "oclusivo", + "ocorrer", + "ocre", + "octogono", + "odalisca", + "odisseia", + "odorifico", + "oersted", + "oeste", + "ofertar", + "ofidio", + "oftalmologo", + "ogiva", + "ogum", + "oigale", + "oitavo", + "oitocentos", + "ojeriza", + "olaria", + "oleoso", + "olfato", + "olhos", + "oliveira", + "olmo", + "olor", + "olvidavel", + "ombudsman", + "omeleteira", + "omitir", + "omoplata", + "onanismo", + "ondular", + "oneroso", + "onomatopeico", + "ontologico", + "onus", + "onze", + "opalescente", + "opcional", + "operistico", + "opio", + "oposto", + "oprobrio", + "optometrista", + "opusculo", + "oratorio", + "orbital", + "orcar", + "orfao", + "orixa", + "orla", + "ornitologo", + "orquidea", + "ortorrombico", + "orvalho", + "osculo", + "osmotico", + "ossudo", + "ostrogodo", + "otario", + "otite", + "ouro", + "ousar", + "outubro", + "ouvir", + "ovario", + "overnight", + "oviparo", + "ovni", + "ovoviviparo", + "ovulo", + "oxala", + "oxente", + "oxiuro", + "oxossi", + "ozonizar", + "paciente", + "pactuar", + "padronizar", + "paete", + "pagodeiro", + "paixao", + "pajem", + "paludismo", + "pampas", + "panturrilha", + "papudo", + "paquistanes", + "pastoso", + "patua", + "paulo", + "pauzinhos", + "pavoroso", + "paxa", + "pazes", + "peao", + "pecuniario", + "pedunculo", + "pegaso", + "peixinho", + "pejorativo", + "pelvis", + "penuria", + "pequno", + "petunia", + "pezada", + "piauiense", + "pictorico", + "pierro", + "pigmeu", + "pijama", + "pilulas", + "pimpolho", + "pintura", + "piorar", + "pipocar", + "piqueteiro", + "pirulito", + "pistoleiro", + "pituitaria", + "pivotar", + "pixote", + "pizzaria", + "plistoceno", + "plotar", + "pluviometrico", + "pneumonico", + "poco", + "podridao", + "poetisa", + "pogrom", + "pois", + "polvorosa", + "pomposo", + "ponderado", + "pontudo", + "populoso", + "poquer", + "porvir", + "posudo", + "potro", + "pouso", + "povoar", + "prazo", + "prezar", + "privilegios", + "proximo", + "prussiano", + "pseudopode", + "psoriase", + "pterossauros", + "ptialina", + "ptolemaico", + "pudor", + "pueril", + "pufe", + "pugilista", + "puir", + "pujante", + "pulverizar", + "pumba", + "punk", + "purulento", + "pustula", + "putsch", + "puxe", + "quatrocentos", + "quetzal", + "quixotesco", + "quotizavel", + "rabujice", + "racista", + "radonio", + "rafia", + "ragu", + "rajado", + "ralo", + "rampeiro", + "ranzinza", + "raptor", + "raquitismo", + "raro", + "rasurar", + "ratoeira", + "ravioli", + "razoavel", + "reavivar", + "rebuscar", + "recusavel", + "reduzivel", + "reexposicao", + "refutavel", + "regurgitar", + "reivindicavel", + "rejuvenescimento", + "relva", + "remuneravel", + "renunciar", + "reorientar", + "repuxo", + "requisito", + "resumo", + "returno", + "reutilizar", + "revolvido", + "rezonear", + "riacho", + "ribossomo", + "ricota", + "ridiculo", + "rifle", + "rigoroso", + "rijo", + "rimel", + "rins", + "rios", + "riqueza", + "respeito", + "rissole", + "ritualistico", + "rivalizar", + "rixa", + "robusto", + "rococo", + "rodoviario", + "roer", + "rogo", + "rojao", + "rolo", + "rompimento", + "ronronar", + "roqueiro", + "rorqual", + "rosto", + "rotundo", + "rouxinol", + "roxo", + "royal", + "ruas", + "rucula", + "rudimentos", + "ruela", + "rufo", + "rugoso", + "ruivo", + "rule", + "rumoroso", + "runico", + "ruptura", + "rural", + "rustico", + "rutilar", + "saariano", + "sabujo", + "sacudir", + "sadomasoquista", + "safra", + "sagui", + "sais", + "samurai", + "santuario", + "sapo", + "saquear", + "sartriano", + "saturno", + "saude", + "sauva", + "saveiro", + "saxofonista", + "sazonal", + "scherzo", + "script", + "seara", + "seborreia", + "secura", + "seduzir", + "sefardim", + "seguro", + "seja", + "selvas", + "sempre", + "senzala", + "sepultura", + "sequoia", + "sestercio", + "setuplo", + "seus", + "seviciar", + "sezonismo", + "shalom", + "siames", + "sibilante", + "sicrano", + "sidra", + "sifilitico", + "signos", + "silvo", + "simultaneo", + "sinusite", + "sionista", + "sirio", + "sisudo", + "situar", + "sivan", + "slide", + "slogan", + "soar", + "sobrio", + "socratico", + "sodomizar", + "soerguer", + "software", + "sogro", + "soja", + "solver", + "somente", + "sonso", + "sopro", + "soquete", + "sorveteiro", + "sossego", + "soturno", + "sousafone", + "sovinice", + "sozinho", + "suavizar", + "subverter", + "sucursal", + "sudoriparo", + "sufragio", + "sugestoes", + "suite", + "sujo", + "sultao", + "sumula", + "suntuoso", + "suor", + "supurar", + "suruba", + "susto", + "suturar", + "suvenir", + "tabuleta", + "taco", + "tadjique", + "tafeta", + "tagarelice", + "taitiano", + "talvez", + "tampouco", + "tanzaniano", + "taoista", + "tapume", + "taquion", + "tarugo", + "tascar", + "tatuar", + "tautologico", + "tavola", + "taxionomista", + "tchecoslovaco", + "teatrologo", + "tectonismo", + "tedioso", + "teflon", + "tegumento", + "teixo", + "telurio", + "temporas", + "tenue", + "teosofico", + "tepido", + "tequila", + "terrorista", + "testosterona", + "tetrico", + "teutonico", + "teve", + "texugo", + "tiara", + "tibia", + "tiete", + "tifoide", + "tigresa", + "tijolo", + "tilintar", + "timpano", + "tintureiro", + "tiquete", + "tiroteio", + "tisico", + "titulos", + "tive", + "toar", + "toboga", + "tofu", + "togoles", + "toicinho", + "tolueno", + "tomografo", + "tontura", + "toponimo", + "toquio", + "torvelinho", + "tostar", + "toto", + "touro", + "toxina", + "trazer", + "trezentos", + "trivialidade", + "trovoar", + "truta", + "tuaregue", + "tubular", + "tucano", + "tudo", + "tufo", + "tuiste", + "tulipa", + "tumultuoso", + "tunisino", + "tupiniquim", + "turvo", + "tutu", + "ucraniano", + "udenista", + "ufanista", + "ufologo", + "ugaritico", + "uiste", + "uivo", + "ulceroso", + "ulema", + "ultravioleta", + "umbilical", + "umero", + "umido", + "umlaut", + "unanimidade", + "unesco", + "ungulado", + "unheiro", + "univoco", + "untuoso", + "urano", + "urbano", + "urdir", + "uretra", + "urgente", + "urinol", + "urna", + "urologo", + "urro", + "ursulina", + "urtiga", + "urupe", + "usavel", + "usbeque", + "usei", + "usineiro", + "usurpar", + "utero", + "utilizar", + "utopico", + "uvular", + "uxoricidio", + "vacuo", + "vadio", + "vaguear", + "vaivem", + "valvula", + "vampiro", + "vantajoso", + "vaporoso", + "vaquinha", + "varziano", + "vasto", + "vaticinio", + "vaudeville", + "vazio", + "veado", + "vedico", + "veemente", + "vegetativo", + "veio", + "veja", + "veludo", + "venusiano", + "verdade", + "verve", + "vestuario", + "vetusto", + "vexatorio", + "vezes", + "viavel", + "vibratorio", + "victor", + "vicunha", + "vidros", + "vietnamita", + "vigoroso", + "vilipendiar", + "vime", + "vintem", + "violoncelo", + "viquingue", + "virus", + "visualizar", + "vituperio", + "viuvo", + "vivo", + "vizir", + "voar", + "vociferar", + "vodu", + "vogar", + "voile", + "volver", + "vomito", + "vontade", + "vortice", + "vosso", + "voto", + "vovozinha", + "voyeuse", + "vozes", + "vulva", + "vupt", + "western", + "xadrez", + "xale", + "xampu", + "xango", + "xarope", + "xaual", + "xavante", + "xaxim", + "xenonio", + "xepa", + "xerox", + "xicara", + "xifopago", + "xiita", + "xilogravura", + "xinxim", + "xistoso", + "xixi", + "xodo", + "xogum", + "xucro", + "zabumba", + "zagueiro", + "zambiano", + "zanzar", + "zarpar", + "zebu", + "zefiro", + "zeloso", + "zenite", + "zumbi" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/ru.json b/coins/monero/src/wallet/seed/classic/ru.json new file mode 100644 index 00000000..579cda33 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/ru.json @@ -0,0 +1,1628 @@ +[ + "абажур", + "абзац", + "абонент", + "абрикос", + "абсурд", + "авангард", + "август", + "авиация", + "авоська", + "автор", + "агат", + "агент", + "агитатор", + "агнец", + "агония", + "агрегат", + "адвокат", + "адмирал", + "адрес", + "ажиотаж", + "азарт", + "азбука", + "азот", + "аист", + "айсберг", + "академия", + "аквариум", + "аккорд", + "акробат", + "аксиома", + "актер", + "акула", + "акция", + "алгоритм", + "алебарда", + "аллея", + "алмаз", + "алтарь", + "алфавит", + "алхимик", + "алый", + "альбом", + "алюминий", + "амбар", + "аметист", + "амнезия", + "ампула", + "амфора", + "анализ", + "ангел", + "анекдот", + "анимация", + "анкета", + "аномалия", + "ансамбль", + "антенна", + "апатия", + "апельсин", + "апофеоз", + "аппарат", + "апрель", + "аптека", + "арабский", + "арбуз", + "аргумент", + "арест", + "ария", + "арка", + "армия", + "аромат", + "арсенал", + "артист", + "архив", + "аршин", + "асбест", + "аскетизм", + "аспект", + "ассорти", + "астроном", + "асфальт", + "атака", + "ателье", + "атлас", + "атом", + "атрибут", + "аудитор", + "аукцион", + "аура", + "афера", + "афиша", + "ахинея", + "ацетон", + "аэропорт", + "бабушка", + "багаж", + "бадья", + "база", + "баклажан", + "балкон", + "бампер", + "банк", + "барон", + "бассейн", + "батарея", + "бахрома", + "башня", + "баян", + "бегство", + "бедро", + "бездна", + "бекон", + "белый", + "бензин", + "берег", + "беседа", + "бетонный", + "биатлон", + "библия", + "бивень", + "бигуди", + "бидон", + "бизнес", + "бикини", + "билет", + "бинокль", + "биология", + "биржа", + "бисер", + "битва", + "бицепс", + "благо", + "бледный", + "близкий", + "блок", + "блуждать", + "блюдо", + "бляха", + "бобер", + "богатый", + "бодрый", + "боевой", + "бокал", + "большой", + "борьба", + "босой", + "ботинок", + "боцман", + "бочка", + "боярин", + "брать", + "бревно", + "бригада", + "бросать", + "брызги", + "брюки", + "бублик", + "бугор", + "будущее", + "буква", + "бульвар", + "бумага", + "бунт", + "бурный", + "бусы", + "бутылка", + "буфет", + "бухта", + "бушлат", + "бывалый", + "быль", + "быстрый", + "быть", + "бюджет", + "бюро", + "бюст", + "вагон", + "важный", + "ваза", + "вакцина", + "валюта", + "вампир", + "ванная", + "вариант", + "вассал", + "вата", + "вафля", + "вахта", + "вдова", + "вдыхать", + "ведущий", + "веер", + "вежливый", + "везти", + "веко", + "великий", + "вена", + "верить", + "веселый", + "ветер", + "вечер", + "вешать", + "вещь", + "веяние", + "взаимный", + "взбучка", + "взвод", + "взгляд", + "вздыхать", + "взлетать", + "взмах", + "взнос", + "взор", + "взрыв", + "взывать", + "взятка", + "вибрация", + "визит", + "вилка", + "вино", + "вирус", + "висеть", + "витрина", + "вихрь", + "вишневый", + "включать", + "вкус", + "власть", + "влечь", + "влияние", + "влюблять", + "внешний", + "внимание", + "внук", + "внятный", + "вода", + "воевать", + "вождь", + "воздух", + "войти", + "вокзал", + "волос", + "вопрос", + "ворота", + "восток", + "впадать", + "впускать", + "врач", + "время", + "вручать", + "всадник", + "всеобщий", + "вспышка", + "встреча", + "вторник", + "вулкан", + "вурдалак", + "входить", + "въезд", + "выбор", + "вывод", + "выгодный", + "выделять", + "выезжать", + "выживать", + "вызывать", + "выигрыш", + "вылезать", + "выносить", + "выпивать", + "высокий", + "выходить", + "вычет", + "вышка", + "выяснять", + "вязать", + "вялый", + "гавань", + "гадать", + "газета", + "гаишник", + "галстук", + "гамма", + "гарантия", + "гастроли", + "гвардия", + "гвоздь", + "гектар", + "гель", + "генерал", + "геолог", + "герой", + "гешефт", + "гибель", + "гигант", + "гильза", + "гимн", + "гипотеза", + "гитара", + "глаз", + "глина", + "глоток", + "глубокий", + "глыба", + "глядеть", + "гнать", + "гнев", + "гнить", + "гном", + "гнуть", + "говорить", + "годовой", + "голова", + "гонка", + "город", + "гость", + "готовый", + "граница", + "грех", + "гриб", + "громкий", + "группа", + "грызть", + "грязный", + "губа", + "гудеть", + "гулять", + "гуманный", + "густой", + "гуща", + "давать", + "далекий", + "дама", + "данные", + "дарить", + "дать", + "дача", + "дверь", + "движение", + "двор", + "дебют", + "девушка", + "дедушка", + "дежурный", + "дезертир", + "действие", + "декабрь", + "дело", + "демократ", + "день", + "депутат", + "держать", + "десяток", + "детский", + "дефицит", + "дешевый", + "деятель", + "джаз", + "джинсы", + "джунгли", + "диалог", + "диван", + "диета", + "дизайн", + "дикий", + "динамика", + "диплом", + "директор", + "диск", + "дитя", + "дичь", + "длинный", + "дневник", + "добрый", + "доверие", + "договор", + "дождь", + "доза", + "документ", + "должен", + "домашний", + "допрос", + "дорога", + "доход", + "доцент", + "дочь", + "дощатый", + "драка", + "древний", + "дрожать", + "друг", + "дрянь", + "дубовый", + "дуга", + "дудка", + "дукат", + "дуло", + "думать", + "дупло", + "дурак", + "дуть", + "духи", + "душа", + "дуэт", + "дымить", + "дыня", + "дыра", + "дыханье", + "дышать", + "дьявол", + "дюжина", + "дюйм", + "дюна", + "дядя", + "дятел", + "егерь", + "единый", + "едкий", + "ежевика", + "ежик", + "езда", + "елка", + "емкость", + "ерунда", + "ехать", + "жадный", + "жажда", + "жалеть", + "жанр", + "жара", + "жать", + "жгучий", + "ждать", + "жевать", + "желание", + "жемчуг", + "женщина", + "жертва", + "жесткий", + "жечь", + "живой", + "жидкость", + "жизнь", + "жилье", + "жирный", + "житель", + "журнал", + "жюри", + "забывать", + "завод", + "загадка", + "задача", + "зажечь", + "зайти", + "закон", + "замечать", + "занимать", + "западный", + "зарплата", + "засыпать", + "затрата", + "захват", + "зацепка", + "зачет", + "защита", + "заявка", + "звать", + "звезда", + "звонить", + "звук", + "здание", + "здешний", + "здоровье", + "зебра", + "зевать", + "зеленый", + "земля", + "зенит", + "зеркало", + "зефир", + "зигзаг", + "зима", + "зиять", + "злак", + "злой", + "змея", + "знать", + "зной", + "зодчий", + "золотой", + "зомби", + "зона", + "зоопарк", + "зоркий", + "зрачок", + "зрение", + "зритель", + "зубной", + "зыбкий", + "зять", + "игла", + "иголка", + "играть", + "идея", + "идиот", + "идол", + "идти", + "иерархия", + "избрать", + "известие", + "изгонять", + "издание", + "излагать", + "изменять", + "износ", + "изоляция", + "изрядный", + "изучать", + "изымать", + "изящный", + "икона", + "икра", + "иллюзия", + "имбирь", + "иметь", + "имидж", + "иммунный", + "империя", + "инвестор", + "индивид", + "инерция", + "инженер", + "иномарка", + "институт", + "интерес", + "инфекция", + "инцидент", + "ипподром", + "ирис", + "ирония", + "искать", + "история", + "исходить", + "исчезать", + "итог", + "июль", + "июнь", + "кабинет", + "кавалер", + "кадр", + "казарма", + "кайф", + "кактус", + "калитка", + "камень", + "канал", + "капитан", + "картина", + "касса", + "катер", + "кафе", + "качество", + "каша", + "каюта", + "квартира", + "квинтет", + "квота", + "кедр", + "кекс", + "кенгуру", + "кепка", + "керосин", + "кетчуп", + "кефир", + "кибитка", + "кивнуть", + "кидать", + "километр", + "кино", + "киоск", + "кипеть", + "кирпич", + "кисть", + "китаец", + "класс", + "клетка", + "клиент", + "клоун", + "клуб", + "клык", + "ключ", + "клятва", + "книга", + "кнопка", + "кнут", + "князь", + "кобура", + "ковер", + "коготь", + "кодекс", + "кожа", + "козел", + "койка", + "коктейль", + "колено", + "компания", + "конец", + "копейка", + "короткий", + "костюм", + "котел", + "кофе", + "кошка", + "красный", + "кресло", + "кричать", + "кровь", + "крупный", + "крыша", + "крючок", + "кубок", + "кувшин", + "кудрявый", + "кузов", + "кукла", + "культура", + "кумир", + "купить", + "курс", + "кусок", + "кухня", + "куча", + "кушать", + "кювет", + "лабиринт", + "лавка", + "лагерь", + "ладонь", + "лазерный", + "лайнер", + "лакей", + "лампа", + "ландшафт", + "лапа", + "ларек", + "ласковый", + "лауреат", + "лачуга", + "лаять", + "лгать", + "лебедь", + "левый", + "легкий", + "ледяной", + "лежать", + "лекция", + "лента", + "лепесток", + "лесной", + "лето", + "лечь", + "леший", + "лживый", + "либерал", + "ливень", + "лига", + "лидер", + "ликовать", + "лиловый", + "лимон", + "линия", + "липа", + "лирика", + "лист", + "литр", + "лифт", + "лихой", + "лицо", + "личный", + "лишний", + "лобовой", + "ловить", + "логика", + "лодка", + "ложка", + "лозунг", + "локоть", + "ломать", + "лоно", + "лопата", + "лорд", + "лось", + "лоток", + "лохматый", + "лошадь", + "лужа", + "лукавый", + "луна", + "лупить", + "лучший", + "лыжный", + "лысый", + "львиный", + "льгота", + "льдина", + "любить", + "людской", + "люстра", + "лютый", + "лягушка", + "магазин", + "мадам", + "мазать", + "майор", + "максимум", + "мальчик", + "манера", + "март", + "масса", + "мать", + "мафия", + "махать", + "мачта", + "машина", + "маэстро", + "маяк", + "мгла", + "мебель", + "медведь", + "мелкий", + "мемуары", + "менять", + "мера", + "место", + "метод", + "механизм", + "мечтать", + "мешать", + "миграция", + "мизинец", + "микрофон", + "миллион", + "минута", + "мировой", + "миссия", + "митинг", + "мишень", + "младший", + "мнение", + "мнимый", + "могила", + "модель", + "мозг", + "мойка", + "мокрый", + "молодой", + "момент", + "монах", + "море", + "мост", + "мотор", + "мохнатый", + "мочь", + "мошенник", + "мощный", + "мрачный", + "мстить", + "мудрый", + "мужчина", + "музыка", + "мука", + "мумия", + "мундир", + "муравей", + "мусор", + "мутный", + "муфта", + "муха", + "мучить", + "мушкетер", + "мыло", + "мысль", + "мыть", + "мычать", + "мышь", + "мэтр", + "мюзикл", + "мягкий", + "мякиш", + "мясо", + "мятый", + "мячик", + "набор", + "навык", + "нагрузка", + "надежда", + "наемный", + "нажать", + "называть", + "наивный", + "накрыть", + "налог", + "намерен", + "наносить", + "написать", + "народ", + "натура", + "наука", + "нация", + "начать", + "небо", + "невеста", + "негодяй", + "неделя", + "нежный", + "незнание", + "нелепый", + "немалый", + "неправда", + "нервный", + "нести", + "нефть", + "нехватка", + "нечистый", + "неясный", + "нива", + "нижний", + "низкий", + "никель", + "нирвана", + "нить", + "ничья", + "ниша", + "нищий", + "новый", + "нога", + "ножницы", + "ноздря", + "ноль", + "номер", + "норма", + "нота", + "ночь", + "ноша", + "ноябрь", + "нрав", + "нужный", + "нутро", + "нынешний", + "нырнуть", + "ныть", + "нюанс", + "нюхать", + "няня", + "оазис", + "обаяние", + "обвинять", + "обгонять", + "обещать", + "обжигать", + "обзор", + "обида", + "область", + "обмен", + "обнимать", + "оборона", + "образ", + "обучение", + "обходить", + "обширный", + "общий", + "объект", + "обычный", + "обязать", + "овальный", + "овес", + "овощи", + "овраг", + "овца", + "овчарка", + "огненный", + "огонь", + "огромный", + "огурец", + "одежда", + "одинокий", + "одобрить", + "ожидать", + "ожог", + "озарение", + "озеро", + "означать", + "оказать", + "океан", + "оклад", + "окно", + "округ", + "октябрь", + "окурок", + "олень", + "опасный", + "операция", + "описать", + "оплата", + "опора", + "оппонент", + "опрос", + "оптимизм", + "опускать", + "опыт", + "орать", + "орбита", + "орган", + "орден", + "орел", + "оригинал", + "оркестр", + "орнамент", + "оружие", + "осадок", + "освещать", + "осень", + "осина", + "осколок", + "осмотр", + "основной", + "особый", + "осуждать", + "отбор", + "отвечать", + "отдать", + "отец", + "отзыв", + "открытие", + "отмечать", + "относить", + "отпуск", + "отрасль", + "отставка", + "оттенок", + "отходить", + "отчет", + "отъезд", + "офицер", + "охапка", + "охота", + "охрана", + "оценка", + "очаг", + "очередь", + "очищать", + "очки", + "ошейник", + "ошибка", + "ощущение", + "павильон", + "падать", + "паек", + "пакет", + "палец", + "память", + "панель", + "папка", + "партия", + "паспорт", + "патрон", + "пауза", + "пафос", + "пахнуть", + "пациент", + "пачка", + "пашня", + "певец", + "педагог", + "пейзаж", + "пельмень", + "пенсия", + "пепел", + "период", + "песня", + "петля", + "пехота", + "печать", + "пешеход", + "пещера", + "пианист", + "пиво", + "пиджак", + "пиковый", + "пилот", + "пионер", + "пирог", + "писать", + "пить", + "пицца", + "пишущий", + "пища", + "план", + "плечо", + "плита", + "плохой", + "плыть", + "плюс", + "пляж", + "победа", + "повод", + "погода", + "подумать", + "поехать", + "пожимать", + "позиция", + "поиск", + "покой", + "получать", + "помнить", + "пони", + "поощрять", + "попадать", + "порядок", + "пост", + "поток", + "похожий", + "поцелуй", + "почва", + "пощечина", + "поэт", + "пояснить", + "право", + "предмет", + "проблема", + "пруд", + "прыгать", + "прямой", + "психолог", + "птица", + "публика", + "пугать", + "пудра", + "пузырь", + "пуля", + "пункт", + "пурга", + "пустой", + "путь", + "пухлый", + "пучок", + "пушистый", + "пчела", + "пшеница", + "пыль", + "пытка", + "пыхтеть", + "пышный", + "пьеса", + "пьяный", + "пятно", + "работа", + "равный", + "радость", + "развитие", + "район", + "ракета", + "рамка", + "ранний", + "рапорт", + "рассказ", + "раунд", + "рация", + "рвать", + "реальный", + "ребенок", + "реветь", + "регион", + "редакция", + "реестр", + "режим", + "резкий", + "рейтинг", + "река", + "религия", + "ремонт", + "рента", + "реплика", + "ресурс", + "реформа", + "рецепт", + "речь", + "решение", + "ржавый", + "рисунок", + "ритм", + "рифма", + "робкий", + "ровный", + "рогатый", + "родитель", + "рождение", + "розовый", + "роковой", + "роль", + "роман", + "ронять", + "рост", + "рота", + "роща", + "рояль", + "рубль", + "ругать", + "руда", + "ружье", + "руины", + "рука", + "руль", + "румяный", + "русский", + "ручка", + "рыба", + "рывок", + "рыдать", + "рыжий", + "рынок", + "рысь", + "рыть", + "рыхлый", + "рыцарь", + "рычаг", + "рюкзак", + "рюмка", + "рябой", + "рядовой", + "сабля", + "садовый", + "сажать", + "салон", + "самолет", + "сани", + "сапог", + "сарай", + "сатира", + "сауна", + "сахар", + "сбегать", + "сбивать", + "сбор", + "сбыт", + "свадьба", + "свет", + "свидание", + "свобода", + "связь", + "сгорать", + "сдвигать", + "сеанс", + "северный", + "сегмент", + "седой", + "сезон", + "сейф", + "секунда", + "сельский", + "семья", + "сентябрь", + "сердце", + "сеть", + "сечение", + "сеять", + "сигнал", + "сидеть", + "сизый", + "сила", + "символ", + "синий", + "сирота", + "система", + "ситуация", + "сиять", + "сказать", + "скважина", + "скелет", + "скидка", + "склад", + "скорый", + "скрывать", + "скучный", + "слава", + "слеза", + "слияние", + "слово", + "случай", + "слышать", + "слюна", + "смех", + "смирение", + "смотреть", + "смутный", + "смысл", + "смятение", + "снаряд", + "снег", + "снижение", + "сносить", + "снять", + "событие", + "совет", + "согласие", + "сожалеть", + "сойти", + "сокол", + "солнце", + "сомнение", + "сонный", + "сообщать", + "соперник", + "сорт", + "состав", + "сотня", + "соус", + "социолог", + "сочинять", + "союз", + "спать", + "спешить", + "спина", + "сплошной", + "способ", + "спутник", + "средство", + "срок", + "срывать", + "стать", + "ствол", + "стена", + "стихи", + "сторона", + "страна", + "студент", + "стыд", + "субъект", + "сувенир", + "сугроб", + "судьба", + "суета", + "суждение", + "сукно", + "сулить", + "сумма", + "сунуть", + "супруг", + "суровый", + "сустав", + "суть", + "сухой", + "суша", + "существо", + "сфера", + "схема", + "сцена", + "счастье", + "счет", + "считать", + "сшивать", + "съезд", + "сынок", + "сыпать", + "сырье", + "сытый", + "сыщик", + "сюжет", + "сюрприз", + "таблица", + "таежный", + "таинство", + "тайна", + "такси", + "талант", + "таможня", + "танец", + "тарелка", + "таскать", + "тахта", + "тачка", + "таять", + "тварь", + "твердый", + "творить", + "театр", + "тезис", + "текст", + "тело", + "тема", + "тень", + "теория", + "теплый", + "терять", + "тесный", + "тетя", + "техника", + "течение", + "тигр", + "типичный", + "тираж", + "титул", + "тихий", + "тишина", + "ткань", + "товарищ", + "толпа", + "тонкий", + "топливо", + "торговля", + "тоска", + "точка", + "тощий", + "традиция", + "тревога", + "трибуна", + "трогать", + "труд", + "трюк", + "тряпка", + "туалет", + "тугой", + "туловище", + "туман", + "тундра", + "тупой", + "турнир", + "тусклый", + "туфля", + "туча", + "туша", + "тыкать", + "тысяча", + "тьма", + "тюльпан", + "тюрьма", + "тяга", + "тяжелый", + "тянуть", + "убеждать", + "убирать", + "убогий", + "убыток", + "уважение", + "уверять", + "увлекать", + "угнать", + "угол", + "угроза", + "удар", + "удивлять", + "удобный", + "уезд", + "ужас", + "ужин", + "узел", + "узкий", + "узнавать", + "узор", + "уйма", + "уклон", + "укол", + "уксус", + "улетать", + "улица", + "улучшать", + "улыбка", + "уметь", + "умиление", + "умный", + "умолять", + "умысел", + "унижать", + "уносить", + "уныние", + "упасть", + "уплата", + "упор", + "упрекать", + "упускать", + "уран", + "урна", + "уровень", + "усадьба", + "усердие", + "усилие", + "ускорять", + "условие", + "усмешка", + "уснуть", + "успеть", + "усыпать", + "утешать", + "утка", + "уточнять", + "утро", + "утюг", + "уходить", + "уцелеть", + "участие", + "ученый", + "учитель", + "ушко", + "ущерб", + "уютный", + "уяснять", + "фабрика", + "фаворит", + "фаза", + "файл", + "факт", + "фамилия", + "фантазия", + "фара", + "фасад", + "февраль", + "фельдшер", + "феномен", + "ферма", + "фигура", + "физика", + "фильм", + "финал", + "фирма", + "фишка", + "флаг", + "флейта", + "флот", + "фокус", + "фольклор", + "фонд", + "форма", + "фото", + "фраза", + "фреска", + "фронт", + "фрукт", + "функция", + "фуражка", + "футбол", + "фыркать", + "халат", + "хамство", + "хаос", + "характер", + "хата", + "хватать", + "хвост", + "хижина", + "хилый", + "химия", + "хирург", + "хитрый", + "хищник", + "хлам", + "хлеб", + "хлопать", + "хмурый", + "ходить", + "хозяин", + "хоккей", + "холодный", + "хороший", + "хотеть", + "хохотать", + "храм", + "хрен", + "хриплый", + "хроника", + "хрупкий", + "художник", + "хулиган", + "хутор", + "царь", + "цвет", + "цель", + "цемент", + "центр", + "цепь", + "церковь", + "цикл", + "цилиндр", + "циничный", + "цирк", + "цистерна", + "цитата", + "цифра", + "цыпленок", + "чадо", + "чайник", + "часть", + "чашка", + "человек", + "чемодан", + "чепуха", + "черный", + "честь", + "четкий", + "чехол", + "чиновник", + "число", + "читать", + "членство", + "чреватый", + "чтение", + "чувство", + "чугунный", + "чудо", + "чужой", + "чукча", + "чулок", + "чума", + "чуткий", + "чучело", + "чушь", + "шаблон", + "шагать", + "шайка", + "шакал", + "шалаш", + "шампунь", + "шанс", + "шапка", + "шарик", + "шасси", + "шатер", + "шахта", + "шашлык", + "швейный", + "швырять", + "шевелить", + "шедевр", + "шейка", + "шелковый", + "шептать", + "шерсть", + "шестерка", + "шикарный", + "шинель", + "шипеть", + "широкий", + "шить", + "шишка", + "шкаф", + "школа", + "шкура", + "шланг", + "шлем", + "шлюпка", + "шляпа", + "шнур", + "шоколад", + "шорох", + "шоссе", + "шофер", + "шпага", + "шпион", + "шприц", + "шрам", + "шрифт", + "штаб", + "штора", + "штраф", + "штука", + "штык", + "шуба", + "шуметь", + "шуршать", + "шутка", + "щадить", + "щедрый", + "щека", + "щель", + "щенок", + "щепка", + "щетка", + "щука", + "эволюция", + "эгоизм", + "экзамен", + "экипаж", + "экономия", + "экран", + "эксперт", + "элемент", + "элита", + "эмблема", + "эмигрант", + "эмоция", + "энергия", + "эпизод", + "эпоха", + "эскиз", + "эссе", + "эстрада", + "этап", + "этика", + "этюд", + "эфир", + "эффект", + "эшелон", + "юбилей", + "юбка", + "южный", + "юмор", + "юноша", + "юрист", + "яблоко", + "явление", + "ягода", + "ядерный", + "ядовитый", + "ядро", + "язва", + "язык", + "яйцо", + "якорь", + "январь", + "японец", + "яркий", + "ярмарка", + "ярость", + "ярус", + "ясный", + "яхта", + "ячейка", + "ящик" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/classic/zh.json b/coins/monero/src/wallet/seed/classic/zh.json new file mode 100644 index 00000000..9d03e9d8 --- /dev/null +++ b/coins/monero/src/wallet/seed/classic/zh.json @@ -0,0 +1,1628 @@ +[ + "的", + "一", + "是", + "在", + "不", + "了", + "有", + "和", + "人", + "这", + "中", + "大", + "为", + "上", + "个", + "国", + "我", + "以", + "要", + "他", + "时", + "来", + "用", + "们", + "生", + "到", + "作", + "地", + "于", + "出", + "就", + "分", + "对", + "成", + "会", + "可", + "主", + "发", + "年", + "动", + "同", + "工", + "也", + "能", + "下", + "过", + "子", + "说", + "产", + "种", + "面", + "而", + "方", + "后", + "多", + "定", + "行", + "学", + "法", + "所", + "民", + "得", + "经", + "十", + "三", + "之", + "进", + "着", + "等", + "部", + "度", + "家", + "电", + "力", + "里", + "如", + "水", + "化", + "高", + "自", + "二", + "理", + "起", + "小", + "物", + "现", + "实", + "加", + "量", + "都", + "两", + "体", + "制", + "机", + "当", + "使", + "点", + "从", + "业", + "本", + "去", + "把", + "性", + "好", + "应", + "开", + "它", + "合", + "还", + "因", + "由", + "其", + "些", + "然", + "前", + "外", + "天", + "政", + "四", + "日", + "那", + "社", + "义", + "事", + "平", + "形", + "相", + "全", + "表", + "间", + "样", + "与", + "关", + "各", + "重", + "新", + "线", + "内", + "数", + "正", + "心", + "反", + "你", + "明", + "看", + "原", + "又", + "么", + "利", + "比", + "或", + "但", + "质", + "气", + "第", + "向", + "道", + "命", + "此", + "变", + "条", + "只", + "没", + "结", + "解", + "问", + "意", + "建", + "月", + "公", + "无", + "系", + "军", + "很", + "情", + "者", + "最", + "立", + "代", + "想", + "已", + "通", + "并", + "提", + "直", + "题", + "党", + "程", + "展", + "五", + "果", + "料", + "象", + "员", + "革", + "位", + "入", + "常", + "文", + "总", + "次", + "品", + "式", + "活", + "设", + "及", + "管", + "特", + "件", + "长", + "求", + "老", + "头", + "基", + "资", + "边", + "流", + "路", + "级", + "少", + "图", + "山", + "统", + "接", + "知", + "较", + "将", + "组", + "见", + "计", + "别", + "她", + "手", + "角", + "期", + "根", + "论", + "运", + "农", + "指", + "几", + "九", + "区", + "强", + "放", + "决", + "西", + "被", + "干", + "做", + "必", + "战", + "先", + "回", + "则", + "任", + "取", + "据", + "处", + "队", + "南", + "给", + "色", + "光", + "门", + "即", + "保", + "治", + "北", + "造", + "百", + "规", + "热", + "领", + "七", + "海", + "口", + "东", + "导", + "器", + "压", + "志", + "世", + "金", + "增", + "争", + "济", + "阶", + "油", + "思", + "术", + "极", + "交", + "受", + "联", + "什", + "认", + "六", + "共", + "权", + "收", + "证", + "改", + "清", + "美", + "再", + "采", + "转", + "更", + "单", + "风", + "切", + "打", + "白", + "教", + "速", + "花", + "带", + "安", + "场", + "身", + "车", + "例", + "真", + "务", + "具", + "万", + "每", + "目", + "至", + "达", + "走", + "积", + "示", + "议", + "声", + "报", + "斗", + "完", + "类", + "八", + "离", + "华", + "名", + "确", + "才", + "科", + "张", + "信", + "马", + "节", + "话", + "米", + "整", + "空", + "元", + "况", + "今", + "集", + "温", + "传", + "土", + "许", + "步", + "群", + "广", + "石", + "记", + "需", + "段", + "研", + "界", + "拉", + "林", + "律", + "叫", + "且", + "究", + "观", + "越", + "织", + "装", + "影", + "算", + "低", + "持", + "音", + "众", + "书", + "布", + "复", + "容", + "儿", + "须", + "际", + "商", + "非", + "验", + "连", + "断", + "深", + "难", + "近", + "矿", + "千", + "周", + "委", + "素", + "技", + "备", + "半", + "办", + "青", + "省", + "列", + "习", + "响", + "约", + "支", + "般", + "史", + "感", + "劳", + "便", + "团", + "往", + "酸", + "历", + "市", + "克", + "何", + "除", + "消", + "构", + "府", + "称", + "太", + "准", + "精", + "值", + "号", + "率", + "族", + "维", + "划", + "选", + "标", + "写", + "存", + "候", + "毛", + "亲", + "快", + "效", + "斯", + "院", + "查", + "江", + "型", + "眼", + "王", + "按", + "格", + "养", + "易", + "置", + "派", + "层", + "片", + "始", + "却", + "专", + "状", + "育", + "厂", + "京", + "识", + "适", + "属", + "圆", + "包", + "火", + "住", + "调", + "满", + "县", + "局", + "照", + "参", + "红", + "细", + "引", + "听", + "该", + "铁", + "价", + "严", + "首", + "底", + "液", + "官", + "德", + "随", + "病", + "苏", + "失", + "尔", + "死", + "讲", + "配", + "女", + "黄", + "推", + "显", + "谈", + "罪", + "神", + "艺", + "呢", + "席", + "含", + "企", + "望", + "密", + "批", + "营", + "项", + "防", + "举", + "球", + "英", + "氧", + "势", + "告", + "李", + "台", + "落", + "木", + "帮", + "轮", + "破", + "亚", + "师", + "围", + "注", + "远", + "字", + "材", + "排", + "供", + "河", + "态", + "封", + "另", + "施", + "减", + "树", + "溶", + "怎", + "止", + "案", + "言", + "士", + "均", + "武", + "固", + "叶", + "鱼", + "波", + "视", + "仅", + "费", + "紧", + "爱", + "左", + "章", + "早", + "朝", + "害", + "续", + "轻", + "服", + "试", + "食", + "充", + "兵", + "源", + "判", + "护", + "司", + "足", + "某", + "练", + "差", + "致", + "板", + "田", + "降", + "黑", + "犯", + "负", + "击", + "范", + "继", + "兴", + "似", + "余", + "坚", + "曲", + "输", + "修", + "故", + "城", + "夫", + "够", + "送", + "笔", + "船", + "占", + "右", + "财", + "吃", + "富", + "春", + "职", + "觉", + "汉", + "画", + "功", + "巴", + "跟", + "虽", + "杂", + "飞", + "检", + "吸", + "助", + "升", + "阳", + "互", + "初", + "创", + "抗", + "考", + "投", + "坏", + "策", + "古", + "径", + "换", + "未", + "跑", + "留", + "钢", + "曾", + "端", + "责", + "站", + "简", + "述", + "钱", + "副", + "尽", + "帝", + "射", + "草", + "冲", + "承", + "独", + "令", + "限", + "阿", + "宣", + "环", + "双", + "请", + "超", + "微", + "让", + "控", + "州", + "良", + "轴", + "找", + "否", + "纪", + "益", + "依", + "优", + "顶", + "础", + "载", + "倒", + "房", + "突", + "坐", + "粉", + "敌", + "略", + "客", + "袁", + "冷", + "胜", + "绝", + "析", + "块", + "剂", + "测", + "丝", + "协", + "诉", + "念", + "陈", + "仍", + "罗", + "盐", + "友", + "洋", + "错", + "苦", + "夜", + "刑", + "移", + "频", + "逐", + "靠", + "混", + "母", + "短", + "皮", + "终", + "聚", + "汽", + "村", + "云", + "哪", + "既", + "距", + "卫", + "停", + "烈", + "央", + "察", + "烧", + "迅", + "境", + "若", + "印", + "洲", + "刻", + "括", + "激", + "孔", + "搞", + "甚", + "室", + "待", + "核", + "校", + "散", + "侵", + "吧", + "甲", + "游", + "久", + "菜", + "味", + "旧", + "模", + "湖", + "货", + "损", + "预", + "阻", + "毫", + "普", + "稳", + "乙", + "妈", + "植", + "息", + "扩", + "银", + "语", + "挥", + "酒", + "守", + "拿", + "序", + "纸", + "医", + "缺", + "雨", + "吗", + "针", + "刘", + "啊", + "急", + "唱", + "误", + "训", + "愿", + "审", + "附", + "获", + "茶", + "鲜", + "粮", + "斤", + "孩", + "脱", + "硫", + "肥", + "善", + "龙", + "演", + "父", + "渐", + "血", + "欢", + "械", + "掌", + "歌", + "沙", + "刚", + "攻", + "谓", + "盾", + "讨", + "晚", + "粒", + "乱", + "燃", + "矛", + "乎", + "杀", + "药", + "宁", + "鲁", + "贵", + "钟", + "煤", + "读", + "班", + "伯", + "香", + "介", + "迫", + "句", + "丰", + "培", + "握", + "兰", + "担", + "弦", + "蛋", + "沉", + "假", + "穿", + "执", + "答", + "乐", + "谁", + "顺", + "烟", + "缩", + "征", + "脸", + "喜", + "松", + "脚", + "困", + "异", + "免", + "背", + "星", + "福", + "买", + "染", + "井", + "概", + "慢", + "怕", + "磁", + "倍", + "祖", + "皇", + "促", + "静", + "补", + "评", + "翻", + "肉", + "践", + "尼", + "衣", + "宽", + "扬", + "棉", + "希", + "伤", + "操", + "垂", + "秋", + "宜", + "氢", + "套", + "督", + "振", + "架", + "亮", + "末", + "宪", + "庆", + "编", + "牛", + "触", + "映", + "雷", + "销", + "诗", + "座", + "居", + "抓", + "裂", + "胞", + "呼", + "娘", + "景", + "威", + "绿", + "晶", + "厚", + "盟", + "衡", + "鸡", + "孙", + "延", + "危", + "胶", + "屋", + "乡", + "临", + "陆", + "顾", + "掉", + "呀", + "灯", + "岁", + "措", + "束", + "耐", + "剧", + "玉", + "赵", + "跳", + "哥", + "季", + "课", + "凯", + "胡", + "额", + "款", + "绍", + "卷", + "齐", + "伟", + "蒸", + "殖", + "永", + "宗", + "苗", + "川", + "炉", + "岩", + "弱", + "零", + "杨", + "奏", + "沿", + "露", + "杆", + "探", + "滑", + "镇", + "饭", + "浓", + "航", + "怀", + "赶", + "库", + "夺", + "伊", + "灵", + "税", + "途", + "灭", + "赛", + "归", + "召", + "鼓", + "播", + "盘", + "裁", + "险", + "康", + "唯", + "录", + "菌", + "纯", + "借", + "糖", + "盖", + "横", + "符", + "私", + "努", + "堂", + "域", + "枪", + "润", + "幅", + "哈", + "竟", + "熟", + "虫", + "泽", + "脑", + "壤", + "碳", + "欧", + "遍", + "侧", + "寨", + "敢", + "彻", + "虑", + "斜", + "薄", + "庭", + "纳", + "弹", + "饲", + "伸", + "折", + "麦", + "湿", + "暗", + "荷", + "瓦", + "塞", + "床", + "筑", + "恶", + "户", + "访", + "塔", + "奇", + "透", + "梁", + "刀", + "旋", + "迹", + "卡", + "氯", + "遇", + "份", + "毒", + "泥", + "退", + "洗", + "摆", + "灰", + "彩", + "卖", + "耗", + "夏", + "择", + "忙", + "铜", + "献", + "硬", + "予", + "繁", + "圈", + "雪", + "函", + "亦", + "抽", + "篇", + "阵", + "阴", + "丁", + "尺", + "追", + "堆", + "雄", + "迎", + "泛", + "爸", + "楼", + "避", + "谋", + "吨", + "野", + "猪", + "旗", + "累", + "偏", + "典", + "馆", + "索", + "秦", + "脂", + "潮", + "爷", + "豆", + "忽", + "托", + "惊", + "塑", + "遗", + "愈", + "朱", + "替", + "纤", + "粗", + "倾", + "尚", + "痛", + "楚", + "谢", + "奋", + "购", + "磨", + "君", + "池", + "旁", + "碎", + "骨", + "监", + "捕", + "弟", + "暴", + "割", + "贯", + "殊", + "释", + "词", + "亡", + "壁", + "顿", + "宝", + "午", + "尘", + "闻", + "揭", + "炮", + "残", + "冬", + "桥", + "妇", + "警", + "综", + "招", + "吴", + "付", + "浮", + "遭", + "徐", + "您", + "摇", + "谷", + "赞", + "箱", + "隔", + "订", + "男", + "吹", + "园", + "纷", + "唐", + "败", + "宋", + "玻", + "巨", + "耕", + "坦", + "荣", + "闭", + "湾", + "键", + "凡", + "驻", + "锅", + "救", + "恩", + "剥", + "凝", + "碱", + "齿", + "截", + "炼", + "麻", + "纺", + "禁", + "废", + "盛", + "版", + "缓", + "净", + "睛", + "昌", + "婚", + "涉", + "筒", + "嘴", + "插", + "岸", + "朗", + "庄", + "街", + "藏", + "姑", + "贸", + "腐", + "奴", + "啦", + "惯", + "乘", + "伙", + "恢", + "匀", + "纱", + "扎", + "辩", + "耳", + "彪", + "臣", + "亿", + "璃", + "抵", + "脉", + "秀", + "萨", + "俄", + "网", + "舞", + "店", + "喷", + "纵", + "寸", + "汗", + "挂", + "洪", + "贺", + "闪", + "柬", + "爆", + "烯", + "津", + "稻", + "墙", + "软", + "勇", + "像", + "滚", + "厘", + "蒙", + "芳", + "肯", + "坡", + "柱", + "荡", + "腿", + "仪", + "旅", + "尾", + "轧", + "冰", + "贡", + "登", + "黎", + "削", + "钻", + "勒", + "逃", + "障", + "氨", + "郭", + "峰", + "币", + "港", + "伏", + "轨", + "亩", + "毕", + "擦", + "莫", + "刺", + "浪", + "秘", + "援", + "株", + "健", + "售", + "股", + "岛", + "甘", + "泡", + "睡", + "童", + "铸", + "汤", + "阀", + "休", + "汇", + "舍", + "牧", + "绕", + "炸", + "哲", + "磷", + "绩", + "朋", + "淡", + "尖", + "启", + "陷", + "柴", + "呈", + "徒", + "颜", + "泪", + "稍", + "忘", + "泵", + "蓝", + "拖", + "洞", + "授", + "镜", + "辛", + "壮", + "锋", + "贫", + "虚", + "弯", + "摩", + "泰", + "幼", + "廷", + "尊", + "窗", + "纲", + "弄", + "隶", + "疑", + "氏", + "宫", + "姐", + "震", + "瑞", + "怪", + "尤", + "琴", + "循", + "描", + "膜", + "违", + "夹", + "腰", + "缘", + "珠", + "穷", + "森", + "枝", + "竹", + "沟", + "催", + "绳", + "忆", + "邦", + "剩", + "幸", + "浆", + "栏", + "拥", + "牙", + "贮", + "礼", + "滤", + "钠", + "纹", + "罢", + "拍", + "咱", + "喊", + "袖", + "埃", + "勤", + "罚", + "焦", + "潜", + "伍", + "墨", + "欲", + "缝", + "姓", + "刊", + "饱", + "仿", + "奖", + "铝", + "鬼", + "丽", + "跨", + "默", + "挖", + "链", + "扫", + "喝", + "袋", + "炭", + "污", + "幕", + "诸", + "弧", + "励", + "梅", + "奶", + "洁", + "灾", + "舟", + "鉴", + "苯", + "讼", + "抱", + "毁", + "懂", + "寒", + "智", + "埔", + "寄", + "届", + "跃", + "渡", + "挑", + "丹", + "艰", + "贝", + "碰", + "拔", + "爹", + "戴", + "码", + "梦", + "芽", + "熔", + "赤", + "渔", + "哭", + "敬", + "颗", + "奔", + "铅", + "仲", + "虎", + "稀", + "妹", + "乏", + "珍", + "申", + "桌", + "遵", + "允", + "隆", + "螺", + "仓", + "魏", + "锐", + "晓", + "氮", + "兼", + "隐", + "碍", + "赫", + "拨", + "忠", + "肃", + "缸", + "牵", + "抢", + "博", + "巧", + "壳", + "兄", + "杜", + "讯", + "诚", + "碧", + "祥", + "柯", + "页", + "巡", + "矩", + "悲", + "灌", + "龄", + "伦", + "票", + "寻", + "桂", + "铺", + "圣", + "恐", + "恰", + "郑", + "趣", + "抬", + "荒", + "腾", + "贴", + "柔", + "滴", + "猛", + "阔", + "辆", + "妻", + "填", + "撤", + "储", + "签", + "闹", + "扰", + "紫", + "砂", + "递", + "戏", + "吊", + "陶", + "伐", + "喂", + "疗", + "瓶", + "婆", + "抚", + "臂", + "摸", + "忍", + "虾", + "蜡", + "邻", + "胸", + "巩", + "挤", + "偶", + "弃", + "槽", + "劲", + "乳", + "邓", + "吉", + "仁", + "烂", + "砖", + "租", + "乌", + "舰", + "伴", + "瓜", + "浅", + "丙", + "暂", + "燥", + "橡", + "柳", + "迷", + "暖", + "牌", + "秧", + "胆", + "详", + "簧", + "踏", + "瓷", + "谱", + "呆", + "宾", + "糊", + "洛", + "辉", + "愤", + "竞", + "隙", + "怒", + "粘", + "乃", + "绪", + "肩", + "籍", + "敏", + "涂", + "熙", + "皆", + "侦", + "悬", + "掘", + "享", + "纠", + "醒", + "狂", + "锁", + "淀", + "恨", + "牲", + "霸", + "爬", + "赏", + "逆", + "玩", + "陵", + "祝", + "秒", + "浙", + "貌" +] \ No newline at end of file diff --git a/coins/monero/src/wallet/seed/mod.rs b/coins/monero/src/wallet/seed/mod.rs new file mode 100644 index 00000000..e34852eb --- /dev/null +++ b/coins/monero/src/wallet/seed/mod.rs @@ -0,0 +1,92 @@ +use core::fmt; + +use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; +use rand_core::{RngCore, CryptoRng}; + +use thiserror::Error; + +pub(crate) mod classic; +use classic::{CLASSIC_SEED_LENGTH, CLASSIC_SEED_LENGTH_WITH_CHECKSUM, ClassicSeed}; + +/// Error when decoding a seed. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Error)] +pub enum SeedError { + #[error("invalid number of words in seed")] + InvalidSeedLength, + #[error("unknown language")] + UnknownLanguage, + #[error("invalid checksum")] + InvalidChecksum, + #[error("english old seeds don't support checksums")] + EnglishOldWithChecksum, + #[error("invalid seed")] + InvalidSeed, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum Language { + Chinese, + English, + Dutch, + French, + Spanish, + German, + Italian, + Portuguese, + Japanese, + Russian, + Esperanto, + Lojban, + EnglishOld, +} + +/// A Monero seed. +// TODO: Add polyseed to enum +#[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)] +pub enum Seed { + Classic(ClassicSeed), +} + +impl fmt::Debug for Seed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Seed::Classic(_) => f.debug_struct("Seed::Classic").finish_non_exhaustive(), + } + } +} + +impl Seed { + /// Create a new seed. + pub fn new(rng: &mut R, lang: Language) -> Seed { + Seed::Classic(ClassicSeed::new(rng, lang)) + } + + /// Parse a seed from a String. + pub fn from_string(words: Zeroizing) -> Result { + match words.split_whitespace().count() { + CLASSIC_SEED_LENGTH | CLASSIC_SEED_LENGTH_WITH_CHECKSUM => { + ClassicSeed::from_string(words).map(Seed::Classic) + } + _ => Err(SeedError::InvalidSeedLength)?, + } + } + + /// Create a Seed from entropy. + pub fn from_entropy(lang: Language, entropy: Zeroizing<[u8; 32]>) -> Option { + ClassicSeed::from_entropy(lang, entropy).map(Seed::Classic) + } + + /// Convert a seed to a String. + pub fn to_string(&self) -> Zeroizing { + match self { + Seed::Classic(seed) => seed.to_string(), + } + } + + /// Return the entropy for this seed. + pub fn entropy(&self) -> Zeroizing<[u8; 32]> { + match self { + Seed::Classic(seed) => seed.entropy(), + } + } +} diff --git a/coins/monero/src/wallet/send/builder.rs b/coins/monero/src/wallet/send/builder.rs index b137dcbf..d1e632cf 100644 --- a/coins/monero/src/wallet/send/builder.rs +++ b/coins/monero/src/wallet/send/builder.rs @@ -5,8 +5,8 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::{ Protocol, wallet::{ - address::MoneroAddress, Fee, SpendableOutput, SignableTransaction, TransactionError, - extra::MAX_TX_EXTRA_NONCE_SIZE, + address::MoneroAddress, Fee, SpendableOutput, Change, SignableTransaction, TransactionError, + extra::MAX_ARBITRARY_DATA_SIZE, }, }; @@ -17,14 +17,14 @@ struct SignableTransactionBuilderInternal { inputs: Vec, payments: Vec<(MoneroAddress, u64)>, - change_address: Option, + change_address: Option, data: Vec>, } impl SignableTransactionBuilderInternal { // Takes in the change address so users don't miss that they have to manually set one // If they don't, all leftover funds will become part of the fee - fn new(protocol: Protocol, fee: Fee, change_address: Option) -> Self { + fn new(protocol: Protocol, fee: Fee, change_address: Option) -> Self { Self { protocol, fee, inputs: vec![], payments: vec![], change_address, data: vec![] } } @@ -77,7 +77,7 @@ impl SignableTransactionBuilder { Self(self.0.clone()) } - pub fn new(protocol: Protocol, fee: Fee, change_address: Option) -> Self { + pub fn new(protocol: Protocol, fee: Fee, change_address: Option) -> Self { Self(Arc::new(RwLock::new(SignableTransactionBuilderInternal::new( protocol, fee, @@ -104,7 +104,7 @@ impl SignableTransactionBuilder { } pub fn add_data(&mut self, data: Vec) -> Result { - if data.len() > MAX_TX_EXTRA_NONCE_SIZE { + if data.len() > MAX_ARBITRARY_DATA_SIZE { Err(TransactionError::TooMuchData)?; } self.0.write().unwrap().add_data(data); @@ -117,7 +117,7 @@ impl SignableTransactionBuilder { read.protocol, read.inputs.clone(), read.payments.clone(), - read.change_address, + read.change_address.clone(), read.data.clone(), read.fee, ) diff --git a/coins/monero/src/wallet/send/mod.rs b/coins/monero/src/wallet/send/mod.rs index 9732c051..0a58cf94 100644 --- a/coins/monero/src/wallet/send/mod.rs +++ b/coins/monero/src/wallet/send/mod.rs @@ -1,4 +1,4 @@ -use core::ops::Deref; +use core::{ops::Deref, fmt}; use thiserror::Error; @@ -7,7 +7,13 @@ use rand::seq::SliceRandom; use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; -use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint}; +use group::Group; +use curve25519_dalek::{ + constants::{ED25519_BASEPOINT_POINT, ED25519_BASEPOINT_TABLE}, + scalar::Scalar, + edwards::EdwardsPoint, +}; +use dalek_ff_group as dfg; #[cfg(feature = "multisig")] use frost::FrostError; @@ -23,8 +29,10 @@ use crate::{ transaction::{Input, Output, Timelock, TransactionPrefix, Transaction}, rpc::{Rpc, RpcError}, wallet::{ - address::MoneroAddress, SpendableOutput, Decoys, PaymentId, ExtraField, Extra, key_image_sort, - uniqueness, shared_key, commitment_mask, amount_encryption, extra::MAX_TX_EXTRA_NONCE_SIZE, + address::{Network, AddressSpec, MoneroAddress}, + ViewPair, SpendableOutput, Decoys, PaymentId, ExtraField, Extra, key_image_sort, uniqueness, + shared_key, commitment_mask, amount_encryption, + extra::{ARBITRARY_DATA_MARKER, MAX_ARBITRARY_DATA_SIZE}, }, }; @@ -47,25 +55,22 @@ struct SendOutput { } impl SendOutput { - fn new( - rng: &mut R, + #[allow(non_snake_case)] + fn internal( unique: [u8; 32], output: (usize, (MoneroAddress, u64)), + ecdh: EdwardsPoint, + R: EdwardsPoint, ) -> (SendOutput, Option<[u8; 8]>) { let o = output.0; let output = output.1; - let r = random_scalar(rng); let (view_tag, shared_key, payment_id_xor) = - shared_key(Some(unique).filter(|_| output.0.meta.kind.guaranteed()), &r, &output.0.view, o); + shared_key(Some(unique).filter(|_| output.0.is_guaranteed()), ecdh, o); ( SendOutput { - R: if !output.0.meta.kind.subaddress() { - &r * &ED25519_BASEPOINT_TABLE - } else { - r * output.0.spend - }, + R, view_tag, dest: ((&shared_key * &ED25519_BASEPOINT_TABLE) + output.0.spend), commitment: Commitment::new(commitment_mask(shared_key), output.1), @@ -77,6 +82,32 @@ impl SendOutput { .map(|id| (u64::from_le_bytes(id) ^ u64::from_le_bytes(payment_id_xor)).to_le_bytes()), ) } + + fn new( + r: &Zeroizing, + unique: [u8; 32], + output: (usize, (MoneroAddress, u64)), + ) -> (SendOutput, Option<[u8; 8]>) { + let address = output.1 .0; + SendOutput::internal( + unique, + output, + r.deref() * address.view, + if !address.is_subaddress() { + r.deref() * &ED25519_BASEPOINT_TABLE + } else { + r.deref() * address.spend + }, + ) + } + + fn change( + ecdh: EdwardsPoint, + unique: [u8; 32], + output: (usize, (MoneroAddress, u64)), + ) -> (SendOutput, Option<[u8; 8]>) { + SendOutput::internal(unique, output, ecdh, ED25519_BASEPOINT_POINT) + } } #[derive(Clone, PartialEq, Eq, Debug, Error)] @@ -93,6 +124,8 @@ pub enum TransactionError { TooManyOutputs, #[error("too much data")] TooMuchData, + #[error("too many inputs/too much arbitrary data")] + TooLargeTransaction, #[error("not enough funds (in {0}, out {1})")] NotEnoughFunds(u64, u64), #[error("wrong spend private key")] @@ -176,26 +209,71 @@ impl Fee { pub struct SignableTransaction { protocol: Protocol, inputs: Vec, - payments: Vec<(MoneroAddress, u64)>, + payments: Vec, data: Vec>, fee: u64, } +/// Specification for a change output. +#[derive(Clone, PartialEq, Eq, Zeroize)] +pub struct Change { + address: MoneroAddress, + view: Option>, +} + +impl fmt::Debug for Change { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Change").field("address", &self.address).finish_non_exhaustive() + } +} + +impl Change { + /// Create a change output specification from a ViewPair, as needed to maintain privacy. + pub fn new(view: &ViewPair, guaranteed: bool) -> Change { + Change { + address: view.address( + Network::Mainnet, + if !guaranteed { + AddressSpec::Standard + } else { + AddressSpec::Featured { subaddress: None, payment_id: None, guaranteed: true } + }, + ), + view: Some(view.view.clone()), + } + } + + /// Create a fingerprintable change output specification which will harm privacy. Only use this + /// if you know what you're doing. + pub fn fingerprintable(address: MoneroAddress) -> Change { + Change { address, view: None } + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Zeroize)] +pub(crate) enum InternalPayment { + Payment((MoneroAddress, u64)), + Change(Change, u64), +} + impl SignableTransaction { - /// Create a signable transaction. If the change address is specified, leftover funds will be - /// sent to it. If the change address isn't specified, up to 16 outputs may be specified, using - /// any leftover funds as a bonus to the fee. The optional data field will be embedded in TX - /// extra. + /// Create a signable transaction. + /// + /// Up to 16 outputs may be present, including the change output. + /// + /// If the change address is specified, leftover funds will be sent to it. + /// + /// Each chunk of data must not exceed MAX_ARBITRARY_DATA_SIZE. pub fn new( protocol: Protocol, inputs: Vec, mut payments: Vec<(MoneroAddress, u64)>, - change_address: Option, + change_address: Option, data: Vec>, fee_rate: Fee, ) -> Result { // Make sure there's only one payment ID - { + let mut has_payment_id = { let mut payment_ids = 0; let mut count = |addr: MoneroAddress| { if addr.payment_id().is_some() { @@ -205,13 +283,14 @@ impl SignableTransaction { for payment in &payments { count(payment.0); } - if let Some(change) = change_address { - count(change); + if let Some(change) = change_address.as_ref() { + count(change.address); } if payment_ids > 1 { Err(TransactionError::MultiplePaymentIds)?; } - } + payment_ids == 1 + }; if inputs.is_empty() { Err(TransactionError::NoInputs)?; @@ -221,55 +300,57 @@ impl SignableTransaction { } for part in &data { - if part.len() > MAX_TX_EXTRA_NONCE_SIZE { + if part.len() > MAX_ARBITRARY_DATA_SIZE { Err(TransactionError::TooMuchData)?; } } - // TODO TX MAX SIZE - - // If we don't have two outputs, as required by Monero, add a second - let mut change = payments.len() == 1; - if change && change_address.is_none() { + // If we don't have two outputs, as required by Monero, error + if (payments.len() == 1) && change_address.is_none() { Err(TransactionError::NoChange)?; } - let outputs = payments.len() + usize::from(change); + let outputs = payments.len() + usize::from(change_address.is_some()); + // Add a dummy payment ID if there's only 2 payments + has_payment_id |= outputs == 2; // Calculate the extra length - let extra = Extra::fee_weight(outputs, data.as_ref()); + let extra = Extra::fee_weight(outputs, has_payment_id, data.as_ref()); + + // This is a extremely heavy fee weight estimation which can only be trusted for two things + // 1) Ensuring we have enough for whatever fee we end up using + // 2) Ensuring we aren't over the max size + let estimated_tx_size = Transaction::fee_weight(protocol, inputs.len(), outputs, extra); + + // The actual limit is half the block size, and for the minimum block size of 300k, that'd be + // 150k + // wallet2 will only create transactions up to 100k bytes however + const MAX_TX_SIZE: usize = 100_000; + + // This uses the weight (estimated_tx_size) despite the BP clawback + // The clawback *increases* the weight, so this will over-estimate, yet it's still safe + if estimated_tx_size >= MAX_TX_SIZE { + Err(TransactionError::TooLargeTransaction)?; + } // Calculate the fee. - let mut fee = - fee_rate.calculate(Transaction::fee_weight(protocol, inputs.len(), outputs, extra)); + let fee = fee_rate.calculate(estimated_tx_size); // Make sure we have enough funds let in_amount = inputs.iter().map(|input| input.commitment().amount).sum::(); - let mut out_amount = payments.iter().map(|payment| payment.1).sum::() + fee; + let out_amount = payments.iter().map(|payment| payment.1).sum::() + fee; if in_amount < out_amount { Err(TransactionError::NotEnoughFunds(in_amount, out_amount))?; } - // If we have yet to add a change output, do so if it's economically viable - if (!change) && change_address.is_some() && (in_amount != out_amount) { - // Check even with the new fee, there's remaining funds - let change_fee = - fee_rate.calculate(Transaction::fee_weight(protocol, inputs.len(), outputs + 1, extra)) - - fee; - if (out_amount + change_fee) < in_amount { - change = true; - out_amount += change_fee; - fee += change_fee; - } - } - - if change { - payments.push((change_address.unwrap(), in_amount - out_amount)); - } - - if payments.len() > MAX_OUTPUTS { + if outputs > MAX_OUTPUTS { Err(TransactionError::TooManyOutputs)?; } + let mut payments = payments.drain(..).map(InternalPayment::Payment).collect::>(); + if let Some(change) = change_address { + payments.push(InternalPayment::Change(change, in_amount - out_amount)); + } + Ok(SignableTransaction { protocol, inputs, payments, data, fee }) } @@ -281,24 +362,109 @@ impl SignableTransaction { // Shuffle the payments self.payments.shuffle(rng); + // Used for all non-subaddress outputs, or if there's only one subaddress output and a change + let tx_key = Zeroizing::new(random_scalar(rng)); + let mut tx_public_key = tx_key.deref() * &ED25519_BASEPOINT_TABLE; + + // If any of these outputs are to a subaddress, we need keys distinct to them + // The only time this *does not* force having additional keys is when the only other output + // is a change output we have the view key for, enabling rewriting rA to aR + let mut has_change_view = false; + let subaddresses = self + .payments + .iter() + .filter(|payment| match *payment { + InternalPayment::Payment(payment) => payment.0.is_subaddress(), + InternalPayment::Change(change, _) => { + if change.view.is_some() { + has_change_view = true; + // It should not be possible to construct a change specification to a subaddress with a + // view key + debug_assert!(!change.address.is_subaddress()); + } + change.address.is_subaddress() + } + }) + .count() != + 0; + + // We need additional keys if we have any subaddresses + let mut additional = subaddresses; + // Unless the above change view key path is taken + if (self.payments.len() == 2) && has_change_view { + additional = false; + } + let modified_change_ecdh = subaddresses && (!additional); + + // If we're using the aR rewrite, update tx_public_key from rG to rB + if modified_change_ecdh { + for payment in &self.payments { + match payment { + InternalPayment::Payment(payment) => { + // This should be the only payment and it should be a subaddress + debug_assert!(payment.0.is_subaddress()); + tx_public_key = tx_key.deref() * payment.0.spend; + } + InternalPayment::Change(_, _) => {} + } + } + debug_assert!(tx_public_key != (tx_key.deref() * &ED25519_BASEPOINT_TABLE)); + } + // Actually create the outputs let mut outputs = Vec::with_capacity(self.payments.len()); let mut id = None; - for payment in self.payments.drain(..).enumerate() { - let (output, payment_id) = SendOutput::new(rng, uniqueness, payment); + for (o, mut payment) in self.payments.drain(..).enumerate() { + // Downcast the change output to a payment output if it doesn't require special handling + // regarding it's view key + payment = if !modified_change_ecdh { + if let InternalPayment::Change(change, amount) = &payment { + InternalPayment::Payment((change.address, *amount)) + } else { + payment + } + } else { + payment + }; + + let (output, payment_id) = match payment { + InternalPayment::Payment(payment) => { + // If this is a subaddress, generate a dedicated r. Else, reuse the TX key + let dedicated = Zeroizing::new(random_scalar(&mut *rng)); + let use_dedicated = additional && payment.0.is_subaddress(); + let r = if use_dedicated { &dedicated } else { &tx_key }; + + let (mut output, payment_id) = SendOutput::new(r, uniqueness, (o, payment)); + if modified_change_ecdh { + debug_assert_eq!(tx_public_key, output.R); + } + // If this used tx_key, randomize its R + if !use_dedicated { + output.R = dfg::EdwardsPoint::random(&mut *rng).0; + } + (output, payment_id) + } + InternalPayment::Change(change, amount) => { + // Instead of rA, use Ra, where R is r * subaddress_spend_key + // change.view must be Some as if it's None, this payment would've been downcast + let ecdh = tx_public_key * change.view.unwrap().deref(); + SendOutput::change(ecdh, uniqueness, (o, (change.address, amount))) + } + }; + outputs.push(output); id = id.or(payment_id); } // Include a random payment ID if we don't actually have one // It prevents transactions from leaking if they're sending to integrated addresses or not - let id = if let Some(id) = id { - id - } else { - let mut id = [0; 8]; - rng.fill_bytes(&mut id); - id - }; + // Only do this if we only have two outputs though, as Monero won't add a dummy if there's + // more than two outputs + if outputs.len() <= 2 { + let mut rand = [0; 8]; + rng.fill_bytes(&mut rand); + id = id.or(Some(rand)); + } let commitments = outputs.iter().map(|output| output.commitment.clone()).collect::>(); let sum = commitments.iter().map(|commitment| commitment.mask).sum(); @@ -308,19 +474,27 @@ impl SignableTransaction { // Create the TX extra let extra = { - let mut extra = Extra::new(outputs.iter().map(|output| output.R).collect()); + let mut extra = Extra::new( + tx_public_key, + if additional { outputs.iter().map(|output| output.R).collect() } else { vec![] }, + ); - let mut id_vec = Vec::with_capacity(1 + 8); - PaymentId::Encrypted(id).serialize(&mut id_vec).unwrap(); - extra.push(ExtraField::Nonce(id_vec)); + if let Some(id) = id { + let mut id_vec = Vec::with_capacity(1 + 8); + PaymentId::Encrypted(id).write(&mut id_vec).unwrap(); + extra.push(ExtraField::Nonce(id_vec)); + } // Include data if present for part in self.data.drain(..) { - extra.push(ExtraField::Nonce(part)); + let mut arb = vec![ARBITRARY_DATA_MARKER]; + arb.extend(part); + extra.push(ExtraField::Nonce(arb)); } - let mut serialized = Vec::with_capacity(Extra::fee_weight(outputs.len(), self.data.as_ref())); - extra.serialize(&mut serialized).unwrap(); + let mut serialized = + Vec::with_capacity(Extra::fee_weight(outputs.len(), id.is_some(), self.data.as_ref())); + extra.write(&mut serialized).unwrap(); serialized }; diff --git a/coins/monero/src/wallet/send/multisig.rs b/coins/monero/src/wallet/send/multisig.rs index e8509029..3c0dbee8 100644 --- a/coins/monero/src/wallet/send/multisig.rs +++ b/coins/monero/src/wallet/send/multisig.rs @@ -4,6 +4,8 @@ use std::{ collections::HashMap, }; +use zeroize::Zeroizing; + use rand_core::{RngCore, CryptoRng, SeedableRng}; use rand_chacha::ChaCha20Rng; @@ -29,7 +31,9 @@ use crate::{ }, transaction::{Input, Transaction}, rpc::Rpc, - wallet::{TransactionError, SignableTransaction, Decoys, key_image_sort, uniqueness}, + wallet::{ + TransactionError, InternalPayment, SignableTransaction, Decoys, key_image_sort, uniqueness, + }, }; /// FROST signing machine to produce a signed transaction. @@ -108,8 +112,19 @@ impl SignableTransaction { transcript.append_message(b"input_shared_key", input.key_offset().to_bytes()); } for payment in &self.payments { - transcript.append_message(b"payment_address", payment.0.to_string().as_bytes()); - transcript.append_message(b"payment_amount", payment.1.to_le_bytes()); + match payment { + InternalPayment::Payment(payment) => { + transcript.append_message(b"payment_address", payment.0.to_string().as_bytes()); + transcript.append_message(b"payment_amount", payment.1.to_le_bytes()); + } + InternalPayment::Change(change, amount) => { + transcript.append_message(b"change_address", change.address.to_string().as_bytes()); + if let Some(view) = change.view.as_ref() { + transcript.append_message(b"change_view_key", Zeroizing::new(view.to_bytes())); + } + transcript.append_message(b"change_amount", amount.to_le_bytes()); + } + } } let mut key_images = vec![]; @@ -123,7 +138,7 @@ impl SignableTransaction { let clsag = ClsagMultisig::new(transcript.clone(), input.key(), inputs[i].clone()); key_images.push(( clsag.H, - keys.current_offset().unwrap_or(dfg::Scalar::zero()).0 + self.inputs[i].key_offset(), + keys.current_offset().unwrap_or_else(dfg::Scalar::zero).0 + self.inputs[i].key_offset(), )); clsags.push(AlgorithmMachine::new(clsag, offset).map_err(TransactionError::FrostError)?); } @@ -248,7 +263,7 @@ impl SignMachine for TransactionSignMachine { // Find out who's included // This may not be a valid set of signers yet the algorithm machine will error if it's not commitments.remove(&self.i); // Remove, if it was included for some reason - let mut included = commitments.keys().into_iter().cloned().collect::>(); + let mut included = commitments.keys().cloned().collect::>(); included.push(self.i); included.sort_unstable(); diff --git a/coins/monero/tests/add_data.rs b/coins/monero/tests/add_data.rs index 1808472a..edb550ab 100644 --- a/coins/monero/tests/add_data.rs +++ b/coins/monero/tests/add_data.rs @@ -1,12 +1,15 @@ -use monero_serai::{rpc::Rpc, wallet::TransactionError, transaction::Transaction}; +use monero_serai::{ + wallet::{TransactionError, extra::MAX_ARBITRARY_DATA_SIZE}, + transaction::Transaction, +}; mod runner; test!( - add_single_data_less_than_255, + add_single_data_less_than_max, ( |_, mut builder: Builder, addr| async move { - let arbitrary_data = vec![b'\0', 254]; + let arbitrary_data = vec![b'\0'; MAX_ARBITRARY_DATA_SIZE - 1]; // make sure we can add to tx let result = builder.add_data(arbitrary_data.clone()); @@ -15,8 +18,7 @@ test!( builder.add_payment(addr, 5); (builder.build().unwrap(), (arbitrary_data,)) }, - |rpc: Rpc, signed: Transaction, mut scanner: Scanner, data: (Vec,)| async move { - let tx = rpc.get_transaction(signed.hash()).await.unwrap(); + |_, tx: Transaction, mut scanner: Scanner, data: (Vec,)| async move { let output = scanner.scan_transaction(&tx).not_locked().swap_remove(0); assert_eq!(output.commitment().amount, 5); assert_eq!(output.arbitrary_data()[0], data.0); @@ -25,10 +27,10 @@ test!( ); test!( - add_multiple_data_less_than_255, + add_multiple_data_less_than_max, ( |_, mut builder: Builder, addr| async move { - let data = vec![b'\0', 254]; + let data = vec![b'\0'; MAX_ARBITRARY_DATA_SIZE - 1]; // Add tx multiple times for _ in 0 .. 5 { @@ -39,8 +41,7 @@ test!( builder.add_payment(addr, 5); (builder.build().unwrap(), data) }, - |rpc: Rpc, signed: Transaction, mut scanner: Scanner, data: Vec| async move { - let tx = rpc.get_transaction(signed.hash()).await.unwrap(); + |_, tx: Transaction, mut scanner: Scanner, data: Vec| async move { let output = scanner.scan_transaction(&tx).not_locked().swap_remove(0); assert_eq!(output.commitment().amount, 5); assert_eq!(output.arbitrary_data(), vec![data; 5]); @@ -49,24 +50,24 @@ test!( ); test!( - add_single_data_more_than_255, + add_single_data_more_than_max, ( |_, mut builder: Builder, addr| async move { - // Make a data that is bigger than 255 bytes - let mut data = vec![b'a'; 256]; + // Make a data that is bigger than the maximum + let mut data = vec![b'a'; MAX_ARBITRARY_DATA_SIZE + 1]; // Make sure we get an error if we try to add it to the TX assert_eq!(builder.add_data(data.clone()), Err(TransactionError::TooMuchData)); - // Reduce data size and retry. The data will now be 255 bytes long, exactly + // Reduce data size and retry. The data will now be 255 bytes long (including the added + // marker), exactly data.pop(); assert!(builder.add_data(data.clone()).is_ok()); builder.add_payment(addr, 5); (builder.build().unwrap(), data) }, - |rpc: Rpc, signed: Transaction, mut scanner: Scanner, data: Vec| async move { - let tx = rpc.get_transaction(signed.hash()).await.unwrap(); + |_, tx: Transaction, mut scanner: Scanner, data: Vec| async move { let output = scanner.scan_transaction(&tx).not_locked().swap_remove(0); assert_eq!(output.commitment().amount, 5); assert_eq!(output.arbitrary_data(), vec![data]); diff --git a/coins/monero/tests/runner.rs b/coins/monero/tests/runner.rs index 149374ba..6626a736 100644 --- a/coins/monero/tests/runner.rs +++ b/coins/monero/tests/runner.rs @@ -1,4 +1,5 @@ use core::ops::Deref; +use std::collections::HashSet; use lazy_static::lazy_static; @@ -10,10 +11,11 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar}; use tokio::sync::Mutex; use monero_serai::{ - Protocol, random_scalar, + random_scalar, wallet::{ - ViewPair, - address::{Network, AddressType, AddressMeta, MoneroAddress}, + ViewPair, Scanner, + address::{Network, AddressType, AddressSpec, AddressMeta, MoneroAddress}, + SpendableOutput, }, rpc::Rpc, }; @@ -41,7 +43,7 @@ pub async fn mine_until_unlocked(rpc: &Rpc, addr: &str, tx_hash: [u8; 32]) { let mut height = rpc.get_height().await.unwrap(); let mut found = false; while !found { - let block = rpc.get_block(height - 1).await.unwrap(); + let block = rpc.get_block_by_number(height - 1).await.unwrap(); found = match block.txs.iter().find(|&&x| x == tx_hash) { Some(_) => true, None => { @@ -56,6 +58,22 @@ pub async fn mine_until_unlocked(rpc: &Rpc, addr: &str, tx_hash: [u8; 32]) { rpc.generate_blocks(addr, 9).await.unwrap(); } +// Mines 60 blocks and returns an unlocked miner TX output. +#[allow(dead_code)] +pub async fn get_miner_tx_output(rpc: &Rpc, view: &ViewPair) -> SpendableOutput { + let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); + + // Mine 60 blocks to unlock a miner TX + let start = rpc.get_height().await.unwrap(); + rpc + .generate_blocks(&view.address(Network::Mainnet, AddressSpec::Standard).to_string(), 60) + .await + .unwrap(); + + let block = rpc.get_block_by_number(start).await.unwrap(); + scanner.scan(rpc, &block).await.unwrap().swap_remove(0).ignore_timelock().swap_remove(0) +} + pub async fn rpc() -> Rpc { let rpc = Rpc::new("http://127.0.0.1:18081".to_string()).unwrap(); @@ -73,7 +91,9 @@ pub async fn rpc() -> Rpc { // Mine 40 blocks to ensure decoy availability rpc.generate_blocks(&addr, 40).await.unwrap(); - assert!(!matches!(rpc.get_protocol().await.unwrap(), Protocol::Unsupported(_))); + + // Make sure we recognize the protocol + rpc.get_protocol().await.unwrap(); rpc } @@ -138,12 +158,12 @@ macro_rules! test { use monero_serai::{ random_scalar, wallet::{ - address::Network, ViewPair, Scanner, SignableTransaction, + address::{Network, AddressSpec}, ViewPair, Scanner, Change, SignableTransaction, SignableTransactionBuilder, }, }; - use runner::{random_address, rpc, mine_until_unlocked}; + use runner::{random_address, rpc, mine_until_unlocked, get_miner_tx_output}; type Builder = SignableTransactionBuilder; @@ -169,33 +189,23 @@ macro_rules! test { keys[&Participant::new(1).unwrap()].group_key().0 }; - let view = ViewPair::new(spend_pub, Zeroizing::new(random_scalar(&mut OsRng))); - let rpc = rpc().await; - let (addr, miner_tx) = { - let mut scanner = - Scanner::from_view(view.clone(), Network::Mainnet, Some(HashSet::new())); - let addr = scanner.address(); + let view = ViewPair::new(spend_pub, Zeroizing::new(random_scalar(&mut OsRng))); + let addr = view.address(Network::Mainnet, AddressSpec::Standard); - // mine 60 blocks to unlock a miner tx - let start = rpc.get_height().await.unwrap(); - rpc.generate_blocks(&addr.to_string(), 60).await.unwrap(); - - let block = rpc.get_block(start).await.unwrap(); - ( - addr, - scanner.scan( - &rpc, - &block - ).await.unwrap().swap_remove(0).ignore_timelock().swap_remove(0) - ) - }; + let miner_tx = get_miner_tx_output(&rpc, &view).await; let builder = SignableTransactionBuilder::new( rpc.get_protocol().await.unwrap(), rpc.get_fee().await.unwrap(), - Some(random_address().2), + Some(Change::new( + &ViewPair::new( + &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE, + Zeroizing::new(random_scalar(&mut OsRng)) + ), + false + )), ); let sign = |tx: SignableTransaction| { @@ -247,7 +257,7 @@ macro_rules! test { mine_until_unlocked(&rpc, &random_address().2.to_string(), signed.hash()).await; let tx = rpc.get_transaction(signed.hash()).await.unwrap(); let scanner = - Scanner::from_view(view.clone(), Network::Mainnet, Some(HashSet::new())); + Scanner::from_view(view.clone(), Some(HashSet::new())); ($first_checks)(rpc.clone(), tx, scanner, state).await }); #[allow(unused_variables, unused_mut, unused_assignments)] @@ -268,7 +278,7 @@ macro_rules! test { #[allow(unused_assignments)] { let scanner = - Scanner::from_view(view.clone(), Network::Mainnet, Some(HashSet::new())); + Scanner::from_view(view.clone(), Some(HashSet::new())); carried_state = Box::new(($checks)(rpc.clone(), tx, scanner, state).await); } diff --git a/coins/monero/tests/scan.rs b/coins/monero/tests/scan.rs new file mode 100644 index 00000000..0938b95b --- /dev/null +++ b/coins/monero/tests/scan.rs @@ -0,0 +1,300 @@ +use rand::RngCore; + +use monero_serai::{transaction::Transaction, wallet::address::SubaddressIndex}; + +mod runner; + +test!( + scan_standard_address, + ( + |_, mut builder: Builder, _| async move { + let view = runner::random_address().1; + let scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); + builder.add_payment(view.address(Network::Mainnet, AddressSpec::Standard), 5); + (builder.build().unwrap(), scanner) + }, + |_, tx: Transaction, _, mut state: Scanner| async move { + let output = state.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + }, + ), +); + +test!( + scan_subaddress, + ( + |_, mut builder: Builder, _| async move { + let subaddress = SubaddressIndex::new(0, 1).unwrap(); + + let view = runner::random_address().1; + let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); + scanner.register_subaddress(subaddress); + + builder.add_payment(view.address(Network::Mainnet, AddressSpec::Subaddress(subaddress)), 5); + (builder.build().unwrap(), (scanner, subaddress)) + }, + |_, tx: Transaction, _, mut state: (Scanner, SubaddressIndex)| async move { + let output = state.0.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + assert_eq!(output.metadata.subaddress, Some(state.1)); + }, + ), +); + +test!( + scan_integrated_address, + ( + |_, mut builder: Builder, _| async move { + let view = runner::random_address().1; + let scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); + + let mut payment_id = [0u8; 8]; + OsRng.fill_bytes(&mut payment_id); + + builder.add_payment(view.address(Network::Mainnet, AddressSpec::Integrated(payment_id)), 5); + (builder.build().unwrap(), (scanner, payment_id)) + }, + |_, tx: Transaction, _, mut state: (Scanner, [u8; 8])| async move { + let output = state.0.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + assert_eq!(output.metadata.payment_id, state.1); + }, + ), +); + +test!( + scan_featured_standard, + ( + |_, mut builder: Builder, _| async move { + let view = runner::random_address().1; + let scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { subaddress: None, payment_id: None, guaranteed: false }, + ), + 5, + ); + (builder.build().unwrap(), scanner) + }, + |_, tx: Transaction, _, mut state: Scanner| async move { + let output = state.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + }, + ), +); + +test!( + scan_featured_subaddress, + ( + |_, mut builder: Builder, _| async move { + let subaddress = SubaddressIndex::new(0, 2).unwrap(); + + let view = runner::random_address().1; + let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); + scanner.register_subaddress(subaddress); + + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: Some(subaddress), + payment_id: None, + guaranteed: false, + }, + ), + 5, + ); + (builder.build().unwrap(), (scanner, subaddress)) + }, + |_, tx: Transaction, _, mut state: (Scanner, SubaddressIndex)| async move { + let output = state.0.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + assert_eq!(output.metadata.subaddress, Some(state.1)); + }, + ), +); + +test!( + scan_featured_integrated, + ( + |_, mut builder: Builder, _| async move { + let view = runner::random_address().1; + let scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); + let mut payment_id = [0u8; 8]; + OsRng.fill_bytes(&mut payment_id); + + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: None, + payment_id: Some(payment_id), + guaranteed: false, + }, + ), + 5, + ); + (builder.build().unwrap(), (scanner, payment_id)) + }, + |_, tx: Transaction, _, mut state: (Scanner, [u8; 8])| async move { + let output = state.0.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + assert_eq!(output.metadata.payment_id, state.1); + }, + ), +); + +test!( + scan_featured_integrated_subaddress, + ( + |_, mut builder: Builder, _| async move { + let subaddress = SubaddressIndex::new(0, 3).unwrap(); + + let view = runner::random_address().1; + let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); + scanner.register_subaddress(subaddress); + + let mut payment_id = [0u8; 8]; + OsRng.fill_bytes(&mut payment_id); + + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: Some(subaddress), + payment_id: Some(payment_id), + guaranteed: false, + }, + ), + 5, + ); + (builder.build().unwrap(), (scanner, payment_id, subaddress)) + }, + |_, tx: Transaction, _, mut state: (Scanner, [u8; 8], SubaddressIndex)| async move { + let output = state.0.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + assert_eq!(output.metadata.payment_id, state.1); + assert_eq!(output.metadata.subaddress, Some(state.2)); + }, + ), +); + +test!( + scan_guaranteed_standard, + ( + |_, mut builder: Builder, _| async move { + let view = runner::random_address().1; + let scanner = Scanner::from_view(view.clone(), None); + + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { subaddress: None, payment_id: None, guaranteed: true }, + ), + 5, + ); + (builder.build().unwrap(), scanner) + }, + |_, tx: Transaction, _, mut state: Scanner| async move { + let output = state.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + }, + ), +); + +test!( + scan_guaranteed_subaddress, + ( + |_, mut builder: Builder, _| async move { + let subaddress = SubaddressIndex::new(1, 0).unwrap(); + + let view = runner::random_address().1; + let mut scanner = Scanner::from_view(view.clone(), None); + scanner.register_subaddress(subaddress); + + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: Some(subaddress), + payment_id: None, + guaranteed: true, + }, + ), + 5, + ); + (builder.build().unwrap(), (scanner, subaddress)) + }, + |_, tx: Transaction, _, mut state: (Scanner, SubaddressIndex)| async move { + let output = state.0.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + assert_eq!(output.metadata.subaddress, Some(state.1)); + }, + ), +); + +test!( + scan_guaranteed_integrated, + ( + |_, mut builder: Builder, _| async move { + let view = runner::random_address().1; + let scanner = Scanner::from_view(view.clone(), None); + let mut payment_id = [0u8; 8]; + OsRng.fill_bytes(&mut payment_id); + + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: None, + payment_id: Some(payment_id), + guaranteed: true, + }, + ), + 5, + ); + (builder.build().unwrap(), (scanner, payment_id)) + }, + |_, tx: Transaction, _, mut state: (Scanner, [u8; 8])| async move { + let output = state.0.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + assert_eq!(output.metadata.payment_id, state.1); + }, + ), +); + +test!( + scan_guaranteed_integrated_subaddress, + ( + |_, mut builder: Builder, _| async move { + let subaddress = SubaddressIndex::new(1, 1).unwrap(); + + let view = runner::random_address().1; + let mut scanner = Scanner::from_view(view.clone(), None); + scanner.register_subaddress(subaddress); + + let mut payment_id = [0u8; 8]; + OsRng.fill_bytes(&mut payment_id); + + builder.add_payment( + view.address( + Network::Mainnet, + AddressSpec::Featured { + subaddress: Some(subaddress), + payment_id: Some(payment_id), + guaranteed: true, + }, + ), + 5, + ); + (builder.build().unwrap(), (scanner, payment_id, subaddress)) + }, + |_, tx: Transaction, _, mut state: (Scanner, [u8; 8], SubaddressIndex)| async move { + let output = state.0.scan_transaction(&tx).not_locked().swap_remove(0); + assert_eq!(output.commitment().amount, 5); + assert_eq!(output.metadata.payment_id, state.1); + assert_eq!(output.metadata.subaddress, Some(state.2)); + }, + ), +); diff --git a/coins/monero/tests/send.rs b/coins/monero/tests/send.rs index 84eb2bb0..66f8e593 100644 --- a/coins/monero/tests/send.rs +++ b/coins/monero/tests/send.rs @@ -1,6 +1,7 @@ use monero_serai::{ - wallet::{ReceivedOutput, SpendableOutput}, + wallet::{extra::Extra, address::SubaddressIndex, ReceivedOutput, SpendableOutput}, transaction::Transaction, + rpc::Rpc, }; mod runner; @@ -49,3 +50,69 @@ test!( }, ), ); + +test!( + // Ideally, this would be single_R, yet it isn't feasible to apply allow(non_snake_case) here + single_r_subaddress_send, + ( + // Consume this builder for an output we can use in the future + // This is needed because we can't get the input from the passed in builder + |_, mut builder: Builder, addr| async move { + builder.add_payment(addr, 1000000000000); + (builder.build().unwrap(), ()) + }, + |_, tx: Transaction, mut scanner: Scanner, _| async move { + let mut outputs = scanner.scan_transaction(&tx).not_locked(); + outputs.sort_by(|x, y| x.commitment().amount.cmp(&y.commitment().amount)); + assert_eq!(outputs[0].commitment().amount, 1000000000000); + outputs + }, + ), + ( + |rpc: Rpc, _, _, mut outputs: Vec| async move { + let change_view = ViewPair::new( + &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE, + Zeroizing::new(random_scalar(&mut OsRng)), + ); + + let mut builder = SignableTransactionBuilder::new( + rpc.get_protocol().await.unwrap(), + rpc.get_fee().await.unwrap(), + Some(Change::new(&change_view, false)), + ); + builder.add_input(SpendableOutput::from(&rpc, outputs.swap_remove(0)).await.unwrap()); + + // Send to a subaddress + let sub_view = ViewPair::new( + &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE, + Zeroizing::new(random_scalar(&mut OsRng)), + ); + builder.add_payment( + sub_view + .address(Network::Mainnet, AddressSpec::Subaddress(SubaddressIndex::new(0, 1).unwrap())), + 1, + ); + (builder.build().unwrap(), (change_view, sub_view)) + }, + |_, tx: Transaction, _, views: (ViewPair, ViewPair)| async move { + // Make sure the change can pick up its output + let mut change_scanner = Scanner::from_view(views.0, Some(HashSet::new())); + assert!(change_scanner.scan_transaction(&tx).not_locked().len() == 1); + + // Make sure the subaddress can pick up its output + let mut sub_scanner = Scanner::from_view(views.1, Some(HashSet::new())); + sub_scanner.register_subaddress(SubaddressIndex::new(0, 1).unwrap()); + let sub_outputs = sub_scanner.scan_transaction(&tx).not_locked(); + assert!(sub_outputs.len() == 1); + assert_eq!(sub_outputs[0].commitment().amount, 1); + + // Make sure only one R was included in TX extra + assert!(Extra::read::<&[u8]>(&mut tx.prefix.extra.as_ref()) + .unwrap() + .keys() + .unwrap() + .1 + .is_none()); + }, + ), +); diff --git a/coins/monero/tests/wallet2_compatibility.rs b/coins/monero/tests/wallet2_compatibility.rs new file mode 100644 index 00000000..113249c0 --- /dev/null +++ b/coins/monero/tests/wallet2_compatibility.rs @@ -0,0 +1,245 @@ +use std::{ + collections::{HashSet, HashMap}, + str::FromStr, +}; + +use rand_core::{OsRng, RngCore}; + +use serde::Deserialize; +use serde_json::json; + +use monero_rpc::{ + monero::{ + Amount, Address, + cryptonote::{hash::Hash, subaddress::Index}, + util::address::PaymentId, + }, + TransferOptions, WalletClient, +}; + +use monero_serai::{ + transaction::Transaction, + wallet::{ + address::{Network, AddressSpec, SubaddressIndex, MoneroAddress}, + extra::{MAX_TX_EXTRA_NONCE_SIZE, Extra}, + Scanner, + }, + rpc::Rpc, +}; + +mod runner; + +async fn make_integrated_address(payment_id: [u8; 8]) -> String { + #[derive(Deserialize, Debug)] + struct IntegratedAddressResponse { + integrated_address: String, + } + + let rpc = Rpc::new("http://127.0.0.1:6061".to_string()).unwrap(); + let res = rpc + .json_rpc_call::( + "make_integrated_address", + Some(json!({ "payment_id": hex::encode(payment_id) })), + ) + .await + .unwrap(); + + res.integrated_address +} + +async fn initialize_rpcs() -> (WalletClient, Rpc, monero_rpc::monero::Address) { + let wallet_rpc = + monero_rpc::RpcClientBuilder::new().build("http://127.0.0.1:6061").unwrap().wallet(); + let daemon_rpc = runner::rpc().await; + + let address_resp = wallet_rpc.get_address(0, None).await; + let wallet_rpc_addr = if address_resp.is_ok() { + address_resp.unwrap().address + } else { + wallet_rpc.create_wallet("wallet".to_string(), None, "English".to_string()).await.unwrap(); + let addr = wallet_rpc.get_address(0, None).await.unwrap().address; + daemon_rpc.generate_blocks(&addr.to_string(), 70).await.unwrap(); + addr + }; + (wallet_rpc, daemon_rpc, wallet_rpc_addr) +} + +async fn from_wallet_rpc_to_self(spec: AddressSpec) { + // initialize rpc + let (wallet_rpc, daemon_rpc, wallet_rpc_addr) = initialize_rpcs().await; + + // make an addr + let (_, view_pair, _) = runner::random_address(); + let addr = Address::from_str(&view_pair.address(Network::Mainnet, spec).to_string()[..]).unwrap(); + + // refresh & make a tx + wallet_rpc.refresh(None).await.unwrap(); + let tx = wallet_rpc + .transfer( + HashMap::from([(addr, Amount::ONE_XMR)]), + monero_rpc::TransferPriority::Default, + TransferOptions::default(), + ) + .await + .unwrap(); + let tx_hash: [u8; 32] = tx.tx_hash.0.try_into().unwrap(); + + // unlock it + runner::mine_until_unlocked(&daemon_rpc, &wallet_rpc_addr.to_string(), tx_hash).await; + + // create the scanner + let mut scanner = Scanner::from_view(view_pair, Some(HashSet::new())); + if let AddressSpec::Subaddress(index) = spec { + scanner.register_subaddress(index); + } + + // retrieve it and confirm + let tx = daemon_rpc.get_transaction(tx_hash).await.unwrap(); + let output = scanner.scan_transaction(&tx).not_locked().swap_remove(0); + + match spec { + AddressSpec::Subaddress(index) => assert_eq!(output.metadata.subaddress, Some(index)), + AddressSpec::Integrated(payment_id) => { + assert_eq!(output.metadata.payment_id, payment_id); + assert_eq!(output.metadata.subaddress, None); + } + _ => assert_eq!(output.metadata.subaddress, None), + } + assert_eq!(output.commitment().amount, 1000000000000); +} + +async_sequential!( + async fn receipt_of_wallet_rpc_tx_standard() { + from_wallet_rpc_to_self(AddressSpec::Standard).await; + } + + async fn receipt_of_wallet_rpc_tx_subaddress() { + from_wallet_rpc_to_self(AddressSpec::Subaddress(SubaddressIndex::new(0, 1).unwrap())).await; + } + + async fn receipt_of_wallet_rpc_tx_integrated() { + let mut payment_id = [0u8; 8]; + OsRng.fill_bytes(&mut payment_id); + from_wallet_rpc_to_self(AddressSpec::Integrated(payment_id)).await; + } +); + +test!( + send_to_wallet_rpc_standard, + ( + |_, mut builder: Builder, _| async move { + // initialize rpc + let (wallet_rpc, _, wallet_rpc_addr) = initialize_rpcs().await; + + // add destination + builder.add_payment( + MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr.to_string()).unwrap(), + 1000000, + ); + (builder.build().unwrap(), (wallet_rpc,)) + }, + |_, tx: Transaction, _, data: (WalletClient,)| async move { + // confirm receipt + data.0.refresh(None).await.unwrap(); + let transfer = + data.0.get_transfer(Hash::from_slice(&tx.hash()), None).await.unwrap().unwrap(); + assert_eq!(transfer.amount.as_pico(), 1000000); + assert_eq!(transfer.subaddr_index, Index { major: 0, minor: 0 }); + }, + ), +); + +test!( + send_to_wallet_rpc_subaddress, + ( + |_, mut builder: Builder, _| async move { + // initialize rpc + let (wallet_rpc, _, _) = initialize_rpcs().await; + + // make the addr + let (subaddress, index) = wallet_rpc.create_address(0, None).await.unwrap(); + + builder.add_payment( + MoneroAddress::from_str(Network::Mainnet, &subaddress.to_string()).unwrap(), + 1000000, + ); + (builder.build().unwrap(), (wallet_rpc, index)) + }, + |_, tx: Transaction, _, data: (WalletClient, u32)| async move { + // confirm receipt + data.0.refresh(None).await.unwrap(); + let transfer = + data.0.get_transfer(Hash::from_slice(&tx.hash()), None).await.unwrap().unwrap(); + assert_eq!(transfer.amount.as_pico(), 1000000); + assert_eq!(transfer.subaddr_index, Index { major: 0, minor: data.1 }); + + // Make sure only one R was included in TX extra + assert!(Extra::read::<&[u8]>(&mut tx.prefix.extra.as_ref()) + .unwrap() + .keys() + .unwrap() + .1 + .is_none()); + }, + ), +); + +test!( + send_to_wallet_rpc_integrated, + ( + |_, mut builder: Builder, _| async move { + // initialize rpc + let (wallet_rpc, _, _) = initialize_rpcs().await; + + // make the addr + let mut payment_id = [0u8; 8]; + OsRng.fill_bytes(&mut payment_id); + let addr = make_integrated_address(payment_id).await; + + builder.add_payment(MoneroAddress::from_str(Network::Mainnet, &addr).unwrap(), 1000000); + (builder.build().unwrap(), (wallet_rpc, payment_id)) + }, + |_, tx: Transaction, _, data: (WalletClient, [u8; 8])| async move { + // confirm receipt + data.0.refresh(None).await.unwrap(); + let transfer = + data.0.get_transfer(Hash::from_slice(&tx.hash()), None).await.unwrap().unwrap(); + assert_eq!(transfer.amount.as_pico(), 1000000); + assert_eq!(transfer.subaddr_index, Index { major: 0, minor: 0 }); + assert_eq!(transfer.payment_id.0, PaymentId::from_slice(&data.1)); + }, + ), +); + +test!( + send_to_wallet_rpc_with_arb_data, + ( + |_, mut builder: Builder, _| async move { + // initialize rpc + let (wallet_rpc, _, wallet_rpc_addr) = initialize_rpcs().await; + + // add destination + builder.add_payment( + MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr.to_string()).unwrap(), + 1000000, + ); + + // Make 2 data that is the full 255 bytes + for _ in 0 .. 2 { + // Subtract 1 since we prefix data with 127 + let data = vec![b'a'; MAX_TX_EXTRA_NONCE_SIZE - 1]; + assert!(builder.add_data(data).is_ok()); + } + + (builder.build().unwrap(), (wallet_rpc,)) + }, + |_, tx: Transaction, _, data: (WalletClient,)| async move { + // confirm receipt + data.0.refresh(None).await.unwrap(); + let transfer = + data.0.get_transfer(Hash::from_slice(&tx.hash()), None).await.unwrap().unwrap(); + assert_eq!(transfer.amount.as_pico(), 1000000); + assert_eq!(transfer.subaddr_index, Index { major: 0, minor: 0 }); + }, + ), +); diff --git a/common/zalloc/LICENSE b/common/zalloc/LICENSE index f05b748b..6779f0ec 100644 --- a/common/zalloc/LICENSE +++ b/common/zalloc/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/contracts/extension/Cargo.toml b/contracts/extension/Cargo.toml deleted file mode 100644 index 9272659e..00000000 --- a/contracts/extension/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "serai-extension" -version = "0.1.0" -description = "An ink! extension for exposing Serai to ink" -license = "AGPL-3.0-only" -repository = "https://github.com/serai-dex/serai/tree/develop/contracts/extension" -authors = ["Luke Parker "] -edition = "2021" -publish = false - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[dependencies] -scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } - -ink_env = { version = "3", default-features = false } -ink_lang = { version = "3", default-features = false } - -[features] -default = ["std"] -std = ["ink_env/std"] -ink-as-dependency = [] diff --git a/contracts/extension/src/lib.rs b/contracts/extension/src/lib.rs deleted file mode 100644 index 1c5a34bc..00000000 --- a/contracts/extension/src/lib.rs +++ /dev/null @@ -1,122 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -use ink_lang as ink; -use ink_env::{Environment, DefaultEnvironment, AccountId}; - -pub type Curve = u16; -pub type Coin = u32; -pub type GlobalValidatorSetId = u32; -pub type ValidatorSetIndex = u8; -pub type Key = Vec; - -#[ink::chain_extension] -pub trait SeraiExtension { - type ErrorCode = (); - - /// Returns the ID for the current global validator set. - #[ink(extension = 0, handle_status = false, returns_result = false)] - fn global_validator_set_id() -> GlobalValidatorSetId; - - /// Returns the amount of active validator sets within the global validator set. - #[ink(extension = 1, handle_status = false, returns_result = false)] - fn validator_sets() -> u8; - - /// Returns the amount of key shares used within the specified validator set. - #[ink(extension = 2, handle_status = false, returns_result = false)] - fn validator_set_shares(set: ValidatorSetIndex) -> u16; - - /// Returns the validator set the specified account is in, along with their amount of shares in - /// that validator set, if they are in a current validator - #[ink(extension = 3, handle_status = false, returns_result = false)] - fn active_validator(account: &AccountId) -> Option<(ValidatorSetIndex, u16)>; -} - -pub struct SeraiEnvironment; -impl Environment for SeraiEnvironment { - const MAX_EVENT_TOPICS: usize = ::MAX_EVENT_TOPICS; - - type AccountId = ::AccountId; - type Balance = ::Balance; - type Hash = ::Hash; - type BlockNumber = ::BlockNumber; - type Timestamp = ::Timestamp; - - type ChainExtension = SeraiExtension; -} - -pub fn test_validators() -> Vec { - vec![ - AccountId::from([1; 32]), - AccountId::from([2; 32]), - AccountId::from([3; 32]), - AccountId::from([4; 32]), - AccountId::from([5; 32]), - ] -} - -pub fn test_register() { - struct ExtensionId; - impl ink_env::test::ChainExtension for ExtensionId { - fn func_id(&self) -> u32 { - 0 - } - - fn call(&mut self, _: &[u8], output: &mut Vec) -> u32 { - // Non-0 global validator set ID - scale::Encode::encode_to(&1u32, output); - 0 - } - } - ink_env::test::register_chain_extension(ExtensionId); - - struct ExtensionSets; - impl ink_env::test::ChainExtension for ExtensionSets { - fn func_id(&self) -> u32 { - 1 - } - - fn call(&mut self, _: &[u8], output: &mut Vec) -> u32 { - // 1 validator set - scale::Encode::encode_to(&1u8, output); - 0 - } - } - ink_env::test::register_chain_extension(ExtensionSets); - - struct ExtensionShares; - impl ink_env::test::ChainExtension for ExtensionShares { - fn func_id(&self) -> u32 { - 2 - } - - fn call(&mut self, _: &[u8], output: &mut Vec) -> u32 { - // 1 key share per validator - scale::Encode::encode_to(&u16::try_from(test_validators().len()).unwrap(), output); - 0 - } - } - ink_env::test::register_chain_extension(ExtensionShares); - - struct ExtensionActive; - impl ink_env::test::ChainExtension for ExtensionActive { - fn func_id(&self) -> u32 { - 3 - } - - fn call(&mut self, input: &[u8], output: &mut Vec) -> u32 { - use scale::Decode; - let potential = AccountId::decode(&mut &input[1 ..]).unwrap(); // TODO: Why is this [1 ..]? - - let mut presence = false; - for validator in test_validators() { - if potential == validator { - presence = true; - } - } - // Validator set 0, 1 key share - scale::Encode::encode_to(&Some((0u8, 1u16)).filter(|_| presence), output); - 0 - } - } - ink_env::test::register_chain_extension(ExtensionActive); -} diff --git a/contracts/multisig/Cargo.toml b/contracts/multisig/Cargo.toml deleted file mode 100644 index 6fb4d08b..00000000 --- a/contracts/multisig/Cargo.toml +++ /dev/null @@ -1,48 +0,0 @@ -[package] -name = "serai-multisig" -version = "0.1.0" -description = "An ink! tracker for Serai's current multisig" -license = "AGPL-3.0-only" -repository = "https://github.com/serai-dex/serai/tree/develop/contracts/multisig" -authors = ["Luke Parker "] -edition = "2021" -publish = false - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[lib] -name = "serai_multisig" -path = "lib.rs" -crate-type = ["cdylib"] - -[dependencies] -scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } -scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } - -ink_primitives = { version = "3", default-features = false } -ink_metadata = { version = "3", default-features = false, features = ["derive"], optional = true } -ink_env = { version = "3", default-features = false } -ink_storage = { version = "3", default-features = false } -ink_lang = { version = "3", default-features = false } - -serai-extension = { path = "../extension", default-features = false } - -[dev-dependencies] -lazy_static = "1" - -[features] -default = ["std"] -std = [ - "scale/std", - "scale-info/std", - - "ink_primitives/std", - "ink_metadata/std", - "ink_env/std", - "ink_storage/std", - - "serai-extension/std", -] -ink-as-dependency = [] diff --git a/contracts/multisig/lib.rs b/contracts/multisig/lib.rs deleted file mode 100644 index 62167a42..00000000 --- a/contracts/multisig/lib.rs +++ /dev/null @@ -1,356 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -use ink_lang as ink; - -use serai_extension::{Curve, GlobalValidatorSetId, ValidatorSetIndex, Key}; - -type KeysHash = [u8; 32]; - -#[allow(clippy::all)] -#[ink::contract(env = serai_extension::SeraiEnvironment)] -mod multisig { - use scale::Encode; - - use ink_storage::{traits::SpreadAllocate, Mapping}; - use ink_env::{hash::Blake2x256, hash_encoded}; - - use super::*; - - /// A contract which tracks the current multisig keys. - /// Mapping of each validator set to their multisigs. - #[ink(storage)] - #[derive(SpreadAllocate)] - pub struct Multisig { - /// Global validator set ID under which this multisig was updated. - /// Used to track if the multisig has been updated to the latest instantiation of a validator - /// set or not. - /// May be behind, and still healthy, if a validator set didn't change despite the global - /// validator set doing so. - updated_at: Mapping, - /// Mapping from a curve's index to the multisig's current public key for it, if it has one. - // This is a mapping due to ink's eager loading. Considering we're right now only considering - // Secp256k1 and Ed25519, it may be notably more efficient to use a Vec here. - // In practice, we're likely discussing up to 7 curves in total, so it may always be better to - // simply use a Vec here, especially since it'd be Vec>. - keys: Mapping<(ValidatorSetIndex, Curve), Key>, - /// Validator + Keys -> Voted already or not. - /// Prevents voting multiple times on the same set of keys. - voted: Mapping<(AccountId, KeysHash), ()>, - /// Global Validator Set ID + Validator + Keys -> Vote Count. - /// Including the GVSID locks it to a specific time period, preventing a validator from joining - /// a set, voting on old keys, and then moving their bond to a new account to vote again. - votes: Mapping<(GlobalValidatorSetId, ValidatorSetIndex, KeysHash), u16>, - } - - /// Event emitted when a new set of multisig keys is voted on. - #[ink(event)] - pub struct Vote { - /// Validator who issued the vote. - #[ink(topic)] - validator: AccountId, - /// Global validator set ID under which keys are being generated. - #[ink(topic)] - global_validator_set: GlobalValidatorSetId, - /// Validator set for which keys are being generated. - #[ink(topic)] - validator_set: ValidatorSetIndex, - /// Hash of the keys voted on. - #[ink(topic)] - hash: KeysHash, - /// Keys voted on. Only present in the first event for a given set of keys. - keys: Option>>, - } - - /// Event emitted when the new keys are fully generated for a validator set, having been fully - /// voted on. - #[ink(event)] - pub struct KeyGen { - #[ink(topic)] - global_validator_set: GlobalValidatorSetId, - #[ink(topic)] - validator_set: ValidatorSetIndex, - #[ink(topic)] - hash: KeysHash, - } - - /// The Multisig error types. - #[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)] - #[cfg_attr(feature = "std", derive(scale_info::TypeInfo))] - pub enum Error { - /// Returned if a validator set hasn't had keys registered for it yet. - NonExistentValidatorSet, - /// Returned if a validator set and curve index doesn't have a key registered for it. - NonExistentKey, - /// Returned if a curve index doesn't exist. - NonExistentCurve, - /// Returned if a non-validator is voting. - NotValidator, - /// Returned if this validator set already generated keys. - AlreadyGeneratedKeys, - /// Returned if this validator has already voted for these keys. - AlreadyVoted, - } - - /// The Multisig result type. - pub type Result = core::result::Result; - - impl Multisig { - /// Deploys the Multisig contract. - #[ink(constructor)] - pub fn new() -> Self { - ink_lang::utils::initialize_contract(|_| {}) - } - - /// Global validator set ID under which a validator set updated their multisig. - #[ink(message)] - pub fn updated_at(&self, validator_set: ValidatorSetIndex) -> Result { - self.updated_at.get(validator_set).ok_or(Error::NonExistentValidatorSet) - } - - /// Returns the key currently in-use for a given validator set and curve. - /// This is then bound to a given chain by applying a network-specific additive offset, as done - /// by the processor. Each chain then has its own way of receiving funds to these keys, leaving - /// this not for usage by wallets, nor the processor which is expected to track events for this - /// information. This is really solely for debugging purposes. - #[ink(message)] - pub fn key(&self, validator_set: ValidatorSetIndex, curve: Curve) -> Result { - self.keys.get((validator_set, curve)).ok_or(Error::NonExistentKey) - } - - // TODO: voted - // TODO: votes - - fn hash(value: &T) -> KeysHash { - let mut output = KeysHash::default(); - hash_encoded::(value, &mut output); - output - } - - /// Vote for a given set of keys. - #[ink(message)] - pub fn vote(&mut self, keys: Vec>) -> Result<()> { - if keys.len() > 256 { - Err(Error::NonExistentCurve)?; - } - - // Make sure they're a valid validator. - let validator = self.env().caller(); - let active_validator = self.env().extension().active_validator(&validator); - if active_validator.is_none() { - Err(Error::NotValidator)?; - } - let (validator_set, shares) = active_validator.unwrap(); - - // Prevent a validator set from generating keys multiple times. Only the first-voted-in keys - // should be acknowledged. - let global_validator_set = self.env().extension().global_validator_set_id(); - if self.updated_at.get(validator_set) == Some(global_validator_set) { - Err(Error::AlreadyGeneratedKeys)?; - } - - // Prevent a validator from voting on keys multiple times. - let keys_hash = Self::hash(&keys); - if self.voted.get((validator, keys_hash)).is_some() { - Err(Error::AlreadyVoted)?; - } - self.voted.insert((validator, keys_hash), &()); - - let votes = - if let Some(votes) = self.votes.get((global_validator_set, validator_set, keys_hash)) { - self.env().emit_event(Vote { - validator, - global_validator_set, - validator_set, - hash: keys_hash, - keys: None, - }); - votes + shares - } else { - self.env().emit_event(Vote { - validator, - global_validator_set, - validator_set, - hash: keys_hash, - keys: Some(keys.clone()), - }); - shares - }; - // We could skip writing this if we've reached consensus, yet best to keep our ducks in a row - self.votes.insert((global_validator_set, validator_set, keys_hash), &votes); - - // If we've reached consensus, action this. - if votes == self.env().extension().validator_set_shares(validator_set) { - self.updated_at.insert(validator_set, &global_validator_set); - for (k, key) in keys.iter().enumerate() { - if let Some(key) = key { - self.keys.insert((validator_set, Curve::try_from(k).unwrap()), key); - } - } - self.env().emit_event(KeyGen { global_validator_set, validator_set, hash: keys_hash }); - } - - Ok(()) - } - } - - #[cfg(test)] - mod tests { - use lazy_static::lazy_static; - - use ink_env::{ - hash::{CryptoHash, Blake2x256}, - AccountId, - topics::PrefixedValue, - }; - use ink_lang as ink; - - use serai_extension::{test_validators, test_register}; - - use super::*; - - type Event = ::Type; - - lazy_static! { - static ref EXPECTED_GLOBAL_VALIDATOR_SET: GlobalValidatorSetId = 1; - static ref EXPECTED_VALIDATOR_SET: ValidatorSetIndex = 0; - static ref KEYS: Vec> = vec![Some(vec![0, 1]), Some(vec![2, 3])]; - static ref EXPECTED_HASH: KeysHash = { - let mut hash = KeysHash::default(); - ink_env::hash_encoded::(&*KEYS, &mut hash); - hash - }; - } - - fn hash_prefixed(prefixed: PrefixedValue) -> [u8; 32] { - let encoded = prefixed.encode(); - let mut hash = KeysHash::default(); - if encoded.len() < 32 { - hash[.. encoded.len()].copy_from_slice(&encoded); - } else { - Blake2x256::hash(&encoded, &mut hash); - } - hash - } - - fn assert_vote( - event: &ink_env::test::EmittedEvent, - expected_validator: AccountId, - expected_keys: Option<()>, - ) { - let decoded_event = ::decode(&mut &event.data[..]) - .expect("encountered invalid contract event data buffer"); - - if let Event::Vote(Vote { - validator, - global_validator_set, - validator_set, - hash, - keys: actual_keys, - }) = decoded_event - { - assert_eq!(validator, expected_validator); - assert_eq!(global_validator_set, *EXPECTED_GLOBAL_VALIDATOR_SET); - assert_eq!(validator_set, *EXPECTED_VALIDATOR_SET); - assert_eq!(hash, *EXPECTED_HASH); - assert_eq!(actual_keys.as_ref(), expected_keys.map(|_| &*KEYS)); - } else { - panic!("invalid Vote event") - } - - let expected_topics = vec![ - hash_prefixed(PrefixedValue { prefix: b"", value: b"Multisig::Vote" }), - hash_prefixed(PrefixedValue { - prefix: b"Multisig::Vote::validator", - value: &expected_validator, - }), - hash_prefixed(PrefixedValue { - prefix: b"Multisig::Vote::global_validator_set", - value: &*EXPECTED_GLOBAL_VALIDATOR_SET, - }), - hash_prefixed(PrefixedValue { - prefix: b"Multisig::Vote::validator_set", - value: &*EXPECTED_VALIDATOR_SET, - }), - hash_prefixed(PrefixedValue { prefix: b"Multisig::Vote::hash", value: &*EXPECTED_HASH }), - ]; - - for (n, (actual_topic, expected_topic)) in - event.topics.iter().zip(expected_topics).enumerate() - { - assert_eq!(actual_topic, &expected_topic, "encountered invalid topic at {}", n); - } - } - - fn assert_key_gen(event: &ink_env::test::EmittedEvent) { - let decoded_event = ::decode(&mut &event.data[..]) - .expect("encountered invalid contract event data buffer"); - - if let Event::KeyGen(KeyGen { global_validator_set, validator_set, hash }) = decoded_event { - assert_eq!(global_validator_set, *EXPECTED_GLOBAL_VALIDATOR_SET); - assert_eq!(validator_set, *EXPECTED_VALIDATOR_SET); - assert_eq!(hash, *EXPECTED_HASH); - } else { - panic!("invalid KeyGen event") - } - - let expected_topics = vec![ - hash_prefixed(PrefixedValue { prefix: b"", value: b"Multisig::KeyGen" }), - hash_prefixed(PrefixedValue { - prefix: b"Multisig::KeyGen::global_validator_set", - value: &*EXPECTED_GLOBAL_VALIDATOR_SET, - }), - hash_prefixed(PrefixedValue { - prefix: b"Multisig::KeyGen::validator_set", - value: &*EXPECTED_VALIDATOR_SET, - }), - hash_prefixed(PrefixedValue { prefix: b"Multisig::KeyGen::hash", value: &*EXPECTED_HASH }), - ]; - - for (n, (actual_topic, expected_topic)) in - event.topics.iter().zip(expected_topics).enumerate() - { - assert_eq!(actual_topic, &expected_topic, "encountered invalid topic at {}", n); - } - } - - /// The default constructor does its job. - #[ink::test] - fn new() { - let multisig = Multisig::new(); - assert_eq!(multisig.updated_at(0), Err(Error::NonExistentValidatorSet)); - } - - /// Non-existent keys error accordingly. - #[ink::test] - fn non_existent_key() { - assert_eq!(Multisig::new().key(0, 0), Err(Error::NonExistentKey)); - } - - #[ink::test] - fn success() { - test_register(); - let mut multisig = Multisig::new(); - - // Test voting on keys works without issue, emitting the keys for the first vote - let mut emitted_events = vec![]; - for (i, validator) in test_validators().iter().enumerate() { - ink_env::test::set_caller::(*validator); - multisig.vote(KEYS.clone()).unwrap(); - - emitted_events = ink_env::test::recorded_events().collect::>(); - // If this is the last validator, it should also trigger a keygen event, hence the + 1 - assert_eq!(emitted_events.len(), (i + 1) + (i / (test_validators().len() - 1))); - assert_vote( - &emitted_events[i], - *validator, - // Only the first event for this hash should have the keys - Some(()).filter(|_| i == 0), - ); - } - - // Since this should have key gen'd, verify that - assert_eq!(multisig.updated_at(0).unwrap(), *EXPECTED_GLOBAL_VALIDATOR_SET); - assert_key_gen(&emitted_events[test_validators().len()]); - } - } -} diff --git a/crypto/ciphersuite/LICENSE b/crypto/ciphersuite/LICENSE index c0617e57..be67c32f 100644 --- a/crypto/ciphersuite/LICENSE +++ b/crypto/ciphersuite/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2022 Luke Parker +Copyright (c) 2021-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crypto/dalek-ff-group/LICENSE b/crypto/dalek-ff-group/LICENSE index f05b748b..6779f0ec 100644 --- a/crypto/dalek-ff-group/LICENSE +++ b/crypto/dalek-ff-group/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crypto/dkg/LICENSE b/crypto/dkg/LICENSE index c0617e57..be67c32f 100644 --- a/crypto/dkg/LICENSE +++ b/crypto/dkg/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2022 Luke Parker +Copyright (c) 2021-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crypto/dleq/LICENSE b/crypto/dleq/LICENSE index c1f47de3..78ab2d01 100644 --- a/crypto/dleq/LICENSE +++ b/crypto/dleq/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2022 Luke Parker, Lee Bousfield +Copyright (c) 2020-2023 Luke Parker, Lee Bousfield Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crypto/ed448/LICENSE b/crypto/ed448/LICENSE index f05b748b..6779f0ec 100644 --- a/crypto/ed448/LICENSE +++ b/crypto/ed448/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crypto/ff-group-tests/LICENSE b/crypto/ff-group-tests/LICENSE index f05b748b..6779f0ec 100644 --- a/crypto/ff-group-tests/LICENSE +++ b/crypto/ff-group-tests/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crypto/frost/LICENSE b/crypto/frost/LICENSE index c0617e57..be67c32f 100644 --- a/crypto/frost/LICENSE +++ b/crypto/frost/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2022 Luke Parker +Copyright (c) 2021-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crypto/multiexp/LICENSE b/crypto/multiexp/LICENSE index f05b748b..6779f0ec 100644 --- a/crypto/multiexp/LICENSE +++ b/crypto/multiexp/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crypto/schnorr/LICENSE b/crypto/schnorr/LICENSE index c0617e57..be67c32f 100644 --- a/crypto/schnorr/LICENSE +++ b/crypto/schnorr/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2022 Luke Parker +Copyright (c) 2021-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/crypto/transcript/LICENSE b/crypto/transcript/LICENSE index f05b748b..6779f0ec 100644 --- a/crypto/transcript/LICENSE +++ b/crypto/transcript/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/deny.toml b/deny.toml index 0909db18..5826699d 100644 --- a/deny.toml +++ b/deny.toml @@ -9,6 +9,11 @@ unmaintained = "warn" ignore = [ "RUSTSEC-2020-0071", # https://github.com/chronotope/chrono/issues/602 + "RUSTSEC-2021-0139", # https://github.com/serai-dex/serai/228 + "RUSTSEC-2021-0145", # https://github.com/serai-dex/serai/225 + "RUSTSEC-2022-0061", # https://github.com/serai-dex/serai/227 + "RUSTSEC-2022-0075", # https://github.com/serai-dex/serai/226 + "RUSTSEC-2022-0076", # https://github.com/serai-dex/serai/226 ] [licenses] @@ -39,11 +44,17 @@ allow-osi-fsf-free = "neither" default = "deny" exceptions = [ + { allow = ["AGPL-3.0"], name = "bitcoin-serai" }, { allow = ["AGPL-3.0"], name = "ethereum-serai" }, + { allow = ["AGPL-3.0"], name = "serai-processor" }, - { allow = ["AGPL-3.0"], name = "serai-extension" }, - { allow = ["AGPL-3.0"], name = "serai-multisig" }, + { allow = ["AGPL-3.0"], name = "tokens-pallet" }, + + { allow = ["AGPL-3.0"], name = "in-instructions-pallet" }, + { allow = ["AGPL-3.0"], name = "in-instructions-client" }, + + { allow = ["AGPL-3.0"], name = "validator-sets-pallet" }, { allow = ["AGPL-3.0"], name = "sp-tendermint" }, { allow = ["AGPL-3.0"], name = "pallet-tendermint" }, @@ -51,6 +62,8 @@ exceptions = [ { allow = ["AGPL-3.0"], name = "serai-runtime" }, { allow = ["AGPL-3.0"], name = "serai-node" }, + + { allow = ["AGPL-3.0"], name = "serai-client" }, ] [[licenses.clarify]] @@ -72,5 +85,4 @@ unknown-git = "deny" allow-registry = ["https://github.com/rust-lang/crates.io-index"] allow-git = [ "https://github.com/serai-dex/substrate", - "https://github.com/hack-ink/array-bytes" ] diff --git a/deploy/coins/bitcoin/Dockerfile b/deploy/coins/bitcoin/Dockerfile index 8bd04599..bb86757c 100644 --- a/deploy/coins/bitcoin/Dockerfile +++ b/deploy/coins/bitcoin/Dockerfile @@ -8,7 +8,7 @@ ENV BITCOIN_DATA=/home/bitcoin/.bitcoin WORKDIR /home/bitcoin RUN apk update \ - && apk --no-cache add ca-certificates gnupg bash su-exec + && apk --no-cache add ca-certificates gnupg bash su-exec # Get Binary # TODO: When bitcoin.org publishes 23.0, retrieve checksums from there. @@ -22,7 +22,7 @@ RUN wget https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/bitcoin-${B # Serai recognizes the builder keys for 16/17 signatures # from the 23.0 release ENV KEYS 152812300785C96444D3334D17565732E08E5E41 0AD83877C1F0CD1EE9BD660AD7CC770B81FD22A8 590B7292695AFFA5B672CBB2E13FC145CD3F4304 948444FCE03B05BA5AB0591EC37B1C1D44C786EE 9EDAFF80E080659604F4A76B2EBB056FD847F8A7 E777299FC265DD04793070EB944D35F9AC3DB76A F4FC70F07310028424EFC20A8E4256593F177720 D1DBF2C4B96F2DEBF4C16654410108112E7EA81F -ENV KEYS2 4DAF18FE948E7A965B30F9457E296D555E7F63A7 28E72909F1717FE9607754F8A7BEB2621678D37D 74E2DEF5D77260B98BC19438099BAD163C70FBFA 71A3B16735405025D447E8F274810B012346C9A6 E463A93F5F3117EEDE6C7316BD02942421F4889F 9D3CC86A72F8494342EA5FD10A41BDC3F4FAFF1C 287AE4CA1187C68C08B49CB2D11BD4F33F1DB499 F9A8737BF4FF5C89C903DF31DD78544CF91B1514 +ENV KEYS2 4DAF18FE948E7A965B30F9457E296D555E7F63A7 28E72909F1717FE9607754F8A7BEB2621678D37D 74E2DEF5D77260B98BC19438099BAD163C70FBFA 71A3B16735405025D447E8F274810B012346C9A6 9D3CC86A72F8494342EA5FD10A41BDC3F4FAFF1C 287AE4CA1187C68C08B49CB2D11BD4F33F1DB499 F9A8737BF4FF5C89C903DF31DD78544CF91B1514 # Use hardcoded prints to get keys from servers. 2 Different servers used. RUN gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys ${KEYS} \ @@ -49,6 +49,3 @@ COPY ./scripts /scripts EXPOSE 8332 8333 18332 18333 18443 18444 VOLUME ["/home/bitcoin/.bitcoin"] - -# Run -CMD ["bitcoind"] diff --git a/deploy/coins/bitcoin/scripts/entry-dev.sh b/deploy/coins/bitcoin/scripts/entry-dev.sh index eaf10bc8..a8525881 100755 --- a/deploy/coins/bitcoin/scripts/entry-dev.sh +++ b/deploy/coins/bitcoin/scripts/entry-dev.sh @@ -1,29 +1,6 @@ #!/bin/sh + RPC_USER="${RPC_USER:=serai}" RPC_PASS="${RPC_PASS:=seraidex}" -# address: bcrt1q7kc7tm3a4qljpw4gg5w73cgya6g9nfydtessgs -# private key: cV9X6E3J9jq7R1XR8uPED2JqFxqcd6KrC8XWPy1GchZj7MA7G9Wx -MINER="${MINER:=bcrt1q7kc7tm3a4qljpw4gg5w73cgya6g9nfydtessgs}" -PRIV_KEY="${PRIV_KEY:=cV9X6E3J9jq7R1XR8uPED2JqFxqcd6KrC8XWPy1GchZj7MA7G9Wx}" -BLOCK_TIME=${BLOCK_TIME:=5} - -bitcoind -regtest -txindex -fallbackfee=0.000001 -rpcuser=$RPC_USER -rpcpassword=$RPC_PASS -rpcallowip=0.0.0.0/0 -rpcbind=127.0.0.1 -rpcbind=$(hostname) & - -# give time to bitcoind to start -while true -do - bitcoin-cli -regtest -rpcuser=$RPC_USER -rpcpassword=$RPC_PASS generatetoaddress 100 $MINER && break - sleep 5 -done - -bitcoin-cli -regtest -rpcuser=$RPC_USER -rpcpassword=$RPC_PASS createwallet "miner" false false $RPC_PASS false false true && -bitcoin-cli -regtest -rpcuser=$RPC_USER -rpcpassword=$RPC_PASS walletpassphrase $RPC_PASS 60 && -bitcoin-cli -regtest -rpcuser=$RPC_USER -rpcpassword=$RPC_PASS importprivkey $PRIV_KEY - -# mine a new block every BLOCK_TIME -while true -do - bitcoin-cli -regtest -rpcuser=$RPC_USER -rpcpassword=$RPC_PASS generatetoaddress 1 $MINER - sleep $BLOCK_TIME -done +bitcoind -regtest -rpcuser=$RPC_USER -rpcpassword=$RPC_PASS -rpcallowip=0.0.0.0/0 -rpcbind=127.0.0.1 -rpcbind=$(hostname) diff --git a/deploy/coins/monero/Dockerfile b/deploy/coins/monero/Dockerfile index 3a91ba41..5ca3ccf8 100644 --- a/deploy/coins/monero/Dockerfile +++ b/deploy/coins/monero/Dockerfile @@ -1,5 +1,5 @@ -# Prepare Environment FROM alpine:latest as builder + # https://downloads.getmonero.org/cli/monero-linux-x64-v0.18.1.0.tar.bz2 # Verification will fail if MONERO_VERSION doesn't match the latest # due to the way monero publishes releases. They overwrite a single hashes.txt file @@ -38,5 +38,3 @@ COPY ./scripts /scripts EXPOSE 18080 18081 VOLUME /home/monero/.bitmonero - -CMD ["monerod"] diff --git a/deploy/coins/monero/scripts/entry-dev.sh b/deploy/coins/monero/scripts/entry-dev.sh index 0f14cea1..262c2c21 100755 --- a/deploy/coins/monero/scripts/entry-dev.sh +++ b/deploy/coins/monero/scripts/entry-dev.sh @@ -9,10 +9,3 @@ BLOCK_TIME=${BLOCK_TIME:=5} monerod --regtest --rpc-access-control-origins * --confirm-external-bind \ --rpc-bind-ip=0.0.0.0 --offline --fixed-difficulty=1 \ --non-interactive --mining-threads 1 --detach - -# give time to monerod to start -while true; do - sleep 5 -done - -# Create wallet from PRIV_KEY in monero wallet diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 23cae952..772a5da1 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -152,6 +152,8 @@ services: volumes: - "./coins/bitcoin/scripts:/scripts" entrypoint: /scripts/entry-dev.sh + ports: + - "18443:18443" ethereum: profiles: diff --git a/docs/Serai.md b/docs/Serai.md index 683bc897..04043f16 100644 --- a/docs/Serai.md +++ b/docs/Serai.md @@ -1,33 +1,14 @@ # Serai Serai is a decentralized execution layer whose validators form multisig wallets -for various connected networks, offering secure decentralized custody of foreign -assets to applications built on it. +for various connected networks, offering secure decentralized control of foreign +coins to applications built on it. Serai is exemplified by Serai DEX, an automated-market-maker (AMM) decentralized -exchange, allowing swapping BTC, ETH, USDC, DAI, and XMR. It is the premier +exchange, allowing swapping Bitcoin, Ether, DAI, and Monero. It is the premier application of Serai. ### Substrate Serai is based on [Substrate](https://docs.substrate.io), a blockchain framework offering a robust infrastructure. - -### Smart Contracts - -Serai offers WASM-based smart contracts. All applications are built over these -contracts, enabling composable interactions within a mutual layer. These -contracts are primarily written in [ink!](https://ink.substrate.io/), a -framework for building contracts in Rust. - -Initially, smart contract deployment will not be enabled. Solely Serai DEX will -be available, due to the variety of economic considerations around securing the -multisig. Serai may expand in the future with more explicitly added -applications, each with tailored economic models, or may enable arbitrary -contract deployment. At this time, we solely plan for Serai DEX's availabiliy. - -### Application Calls - -Applications, such as Serai DEX, may be called via calling their relevant smart -contracts. At a low level, this is done via specifying the address of the -contract being interacted with, along with SCALE-encoded calldata. diff --git a/docs/integrations/Ethereum.md b/docs/integrations/Ethereum.md index 48dbec75..e66a1f5b 100644 --- a/docs/integrations/Ethereum.md +++ b/docs/integrations/Ethereum.md @@ -9,11 +9,11 @@ Ethereum addresses are 20-byte hashes. Ethereum In Instructions are present via being appended to the calldata transferring funds to Serai. `origin` is automatically set to the party from which funds are being transferred. For an ERC20, this is `from`. For ETH, this -is the caller. `data` is limited to 255 bytes. +is the caller. ### Out Instructions -`data` is limited to 255 bytes. +`data` is limited to 512 bytes. If `data` is provided, the Ethereum Router will call a contract-calling child contract in order to sandbox it. The first byte of `data` designates which child diff --git a/docs/integrations/Instructions.md b/docs/integrations/Instructions.md index 18c82396..12f1753d 100644 --- a/docs/integrations/Instructions.md +++ b/docs/integrations/Instructions.md @@ -3,90 +3,93 @@ Instructions are used to communicate with networks connected to Serai, and they come in two forms: - - In Instructions are [Application Calls](../Serai.md#application-calls), -paired with incoming funds. Encoded in transactions on connected networks, -Serai will parse out instructions when it receives funds, executing the included -calls. + - In Instructions are programmable specifications paired with incoming coins, +encoded into transactions on connected networks. Serai will parse included +instructions when it receives coins, executing the included specs. - - Out Instructions detail how to transfer assets, either to a Serai address or -an address native to the asset in question. + - Out Instructions detail how to transfer coins, either to a Serai address or +an address native to the coin in question. A transaction containing an In Instruction and an Out Instruction (to a native -address) will receive funds to Serai and send funds from Serai, without +address) will receive coins to Serai and send coins from Serai, without requiring directly performing any transactions on Serai itself. All instructions are encoded under [Shorthand](#shorthand). Shorthand provides frequent use cases to create minimal data representations on connected networks. Instructions are interpreted according to their non-Serai network. Addresses -have no validation performed, beyond being a valid enum entry (when applicable) -of the correct length, unless otherwise noted. If the processor is instructed to -act on invalid data, or send to itself, it will drop the entire instruction. +have no validation performed unless otherwise noted. If the processor is +instructed to act on invalid data, it will drop the entire instruction. ### Serialization - - Numbers are exclusively unsigned and encoded as compact integers under -SCALE. - - Enums are prefixed by an ordinal byte of their type, followed by their -actual values. - - Vectors are prefixed by their length. - - In Instruction fields are numbered and sequentially encoded, allowing -omission, each prefixed by an ordinal byte. This is due to its fields being more -frequently omitted than not, making their presence what's notable. - - All other types have their fields sequentially encoded with no markers. +Instructions are SCALE encoded. -Certain fields may be omitted depending on the network in question. +### Application Call -### In Instructions + - `application` (u16): The application of Serai to call. Currently, only 0, +Serai DEX is valid. + - `data` (Data): The data to call the application with. - - `origin` (Address): Address from the network of origin which sent funds in. - - `target` (Address): The ink! contract to transfer the incoming funds to. - - `data` (Vec\): The data to call `target` with. +### In Instruction + +InInstruction is an enum of SeraiAddress and ApplicationCall. + +The specified target will be minted an appropriate amount of the respective +Serai token. If an Application Call, the encoded call will be executed. + +### Refundable In Instruction + + - `origin` (Option\): Address, from the network of +origin, which sent coins in. + - `instruction` (InInstruction): The action to perform with the +incoming coins. Networks may automatically provide `origin`. If they do, the instruction may -still provide `origin`, overriding the automatically provided value. If no -`origin` is provided, the instruction is dropped. +still provide `origin`, overriding the automatically provided value. -Upon receiving funds, the respective Serai Asset contract is called, minting the -appropriate amount of coins, and transferring them to `target`, calling it with -the attached data. +If the instruction fails, coins are scheduled to be returned to `origin`, +if provided. -If the instruction fails, funds are scheduled to be returned to `origin`. +### Out Instruction -### Out Instructions + - `address` (ExternalAddress): Address to transfer the coins included with +this instruction to. + - `data` (Option): Data to include when transferring coins. - - `destination` (Enum { Native(Address), Serai(Address) }): Address to receive -funds to. - - `data` (Option\>): The data to call -the target with. +No validation of external addresses/data is performed on-chain. If data is +specified for a chain not supporting data, it is silently dropped. -Transfer the funds included with this instruction to the specified address with -the specified data. Asset contracts perform no validation on native -addresses/data. +### Destination + +Destination is an enum of SeraiAddress and OutInstruction. ### Shorthand -Shorthand is an enum which expands to an In Instruction. +Shorthand is an enum which expands to an Refundable In Instruction. ##### Raw -Raw Shorthand encodes a raw In Instruction with no further processing. This is -a verbose fallback option for infrequent use cases not covered by Shorthand. +Raw Shorthand encodes a raw Refundable In Instruction in a Data, with no further +processing. This is a verbose fallback option for infrequent use cases not +covered by Shorthand. ##### Swap - - `origin` (Option\
): In Instruction's `origin`. - - `coin` (Coin): Coin to swap funds for. - - `minimum` (Amount): Minimum amount of `coin` to receive. - - `out` (Out Instruction): Final destination for funds. + - `origin` (Option\): Refundable In Instruction's `origin`. + - `coin` (Coin): Coin to swap funds for. + - `minimum` (Amount): Minimum amount of `coin` to receive. + - `out` (Destination): Final destination for funds. which expands to: ``` -In Instruction { +RefundableInInstruction { origin, - target: Router, - data: swap(Incoming Asset, out, minimum) + instruction: ApplicationCall { + application: DEX, + data: swap(Incoming Asset, coin, minimum, out) + } } ``` @@ -99,19 +102,23 @@ where `swap` is a function which: ##### Add Liquidity - - `origin` (Option\
): In Instruction's `origin`. - - `minimum` (Amount): Minimum amount of SRI to receive. - - `gas` (Amount): Amount of SRI to send to `address` to cover -gas in the future. - - `address` (Address): Account to send the created liquidity tokens. + - `origin` (Option\): Refundable In Instruction's `origin`. + - `minimum` (Amount): Minimum amount of SRI tokens to swap +half for. + - `gas` (Amount): Amount of SRI to send to `address` to +cover gas in the future. + - `address` (Address): Account to send the created liquidity +tokens. which expands to: ``` -In Instruction { +RefundableInInstruction { origin, - target: Router, - data: swap_and_add_liquidity(Incoming Asset, address, minimum, gas) + instruction: ApplicationCall { + application: DEX, + data: swap_and_add_liquidity(Incoming Asset, minimum, gas, address) + } } ``` @@ -120,5 +127,5 @@ where `swap_and_add_liquidity` is a function which: 1) Swaps half of the incoming funds for SRI. 2) Checks the amount of SRI received is greater than `minimum`. 3) Calls `swap_and_add_liquidity` with the amount of SRI received - `gas`, and -a matching amount of the incoming asset. +a matching amount of the incoming coin. 4) Transfers any leftover funds to `address`. diff --git a/docs/integrations/Scenarios.md b/docs/integrations/Scenarios.md deleted file mode 100644 index 5a7c8c75..00000000 --- a/docs/integrations/Scenarios.md +++ /dev/null @@ -1,98 +0,0 @@ -# Scenarios - -### Pong - -Pong has Serai receive funds, just to return them. It's a demonstration of the -in/out flow. - -``` -Shorthand::Raw( - In Instruction { - target: Incoming Asset Contract, - data: native_transfer(Incoming Asset Sender) - } -) -``` - -### Wrap - -Wrap wraps an asset from a connected chain into a Serai Asset, making it usable -with applications on Serai, such as Serai DEX. - -``` -Shorthand::Raw( - In Instruction { - target: Serai Address - } -) -``` - -### Swap SRI to Bitcoin - -For a SRI to Bitcoin swap, a SRI holder would perform an -[Application Call](../Serai.md#application-calls) to Serai DEX, purchasing -seraiBTC. Once they have seraiBTC, they are able to call `native_transfer`, -transferring the BTC underlying the seraiBTC to a specified Bitcoin address. - -### Swap Bitcoin to Monero - -For a Bitcoin to Monero swap, the following Shorthand would be used. - -``` -Shorthand::Swap { - coin: Monero, - minimum: Minimum Monero from Swap, - out: Monero Address -} -``` - - This Shorthand is expected to generally take: - - - 1 byte to identify as Swap. - - 1 byte to not override `origin`. - - 1 byte for `coin`. - - 4 bytes for `minimum`. - - 1 byte for `out`'s `destination`'s ordinal byte. - - 65 bytes for `out`'s `destination`'s address. - - 1 byte to not include `data` in `out`. - -Or 74 bytes. - -### Add Liquidity (Fresh) - -For a user who has never used Serai before, they have three requirements to add -liquidity: - - - Minting the Serai asset they wish to add liquidity for - - Acquiring Serai, as liquidity is symmetric - - Acquiring Serai for gas fees - -The Add Liquidity Shorthand enables all three of these actions, and actually -adding the liquidity, in just one transaction from a connected network. - -``` -Shorthand::AddLiquidity { - minimum: Minimum SRI from Swap, - gas: Amount of SRI to keep for gas - address: Serai address for the liquidity tokens and gas -} -``` - -For adding liquidity from Bitcoin, this Shorthand is expected to generally take: - - - 1 byte to identify as Add Liquidity. - - 1 byte to not override `origin`. - - 5 bytes for `minimum`. - - 4 bytes for `gas`. - - 32 bytes for `address`. - -Or 43 bytes. - -### Add Liquidity (SRI Holder) - -For a user who already has SRI, they solely need to have the asset they wish to -add liquidity for via their SRI. They can either purchase it from Serai DEX, or -wrap it as detailed above. - -Once they have both their SRI and the asset they wish to provide liquidity for, -they would use a Serai transaction to call the DEX, adding the liquidity. diff --git a/docs/protocol/Constants.md b/docs/protocol/Constants.md index 2cbe45b9..8ed0524f 100644 --- a/docs/protocol/Constants.md +++ b/docs/protocol/Constants.md @@ -5,41 +5,33 @@ These are the list of types used to represent various properties within the protocol. -| Alias | Shorthand | Type | -|-------------------------|-----------|----------| -| Amount | Amount | u64 | -| Curve | Curve | u16 | -| Coin | Coin | u32 | -| Global Validator Set ID | GVSID | u32 | -| Validator Set Index | VS | u8 | -| Key | Key | Vec\ | - -### Curves - -Integer IDs for various curves. It should be noted some curves may be the same, -yet have distinct IDs due to having different basepoints, and accordingly -different keys. For such cases, the processor is expected to create one secret -per curve, and then use DLEq proofs to port keys to other basepoints as needed. - -| Curve | ID | -|-----------|----| -| Secp256k1 | 0 | -| Ed25519 | 1 | +| Alias | Type | +|------------------------|----------------------------------------------| +| SeraiAddress | sr25519::Public (unchecked [u8; 32] wrapper) | +| Amount | u64 | +| Coin | u32 | +| Session | u32 | +| Validator Set Index | u16 | +| Validator Set Instance | (Session, Validator Set Index) | +| Key | BoundedVec\ | +| ExternalAddress | BoundedVec\ | +| Data | BoundedVec\ | ### Networks -Every network connected to Serai operates over a specific curve. While the -processor generates keys for curves, these keys are bound to specific networks -via an additive offset created by hashing the network's name (among other -things). The network's key is used for all coins on that network. +Every network connected to Serai operates over a specific curve. The processor +generates a distinct set of keys per network. Beyond the key-generation itself +being isolated, the generated keys are further bound to their respective +networks via an additive offset created by hashing the network's name (among +other properties). The network's key is used for all coins on that network. Networks are not acknowledged by the Serai network, solely by the processor. -| Network | Curve | -|----------|-------| -| Bitcoin | 0 | -| Ethereum | 0 | -| Monero | 1 | +| Network | Curve | +|----------|-----------| +| Bitcoin | Secp256k1 | +| Ethereum | Secp256k1 | +| Monero | Ed25519 | ### Coins @@ -47,8 +39,8 @@ Coins exist over a network and have a distinct integer ID. | Coin | Network | ID | |----------|----------|----| -| Bitcoin | Bitcoin | 0 | -| Ethereum | Ethereum | 1 | -| USDC | Ethereum | 2 | +| Serai | Serai | 0 | +| Bitcoin | Bitcoin | 1 | +| Ether | Ethereum | 2 | | DAI | Ethereum | 3 | | Monero | Monero | 4 | diff --git a/docs/protocol/Multisig.md b/docs/protocol/Multisig.md deleted file mode 100644 index 7a572a98..00000000 --- a/docs/protocol/Multisig.md +++ /dev/null @@ -1,35 +0,0 @@ -# Multisig - -Multisigs are confirmed on-chain by the `Multisig` contract. While the processor -does create the multisig, and sign for it, making it irrelevant to the chain, -confirming it on-chain solves the question of if the multisig was successfully -created or not. If each processor simply asked all other processors for -confirmation, votes lost to the network would create an inconsistent view. This -is a form of the Byzantine Generals Problem, which can be resolved by placing -votes within a BFT system. - -Confirmation requires all participants confirm the new set of keys. While this -isn't BFT, despite the voting process being BFT, it avoids the scenario where -only t (where t is the BFT threshold, as used in the t-of-n multisig) -successfully generated shares, actually creating a t-of-t multisig in practice, -which is not BFT. This does mean a single node can delay a churn, which is -expected to be handled via a combination of slashing, and if necessary, removal. - -Validators are allowed to vote multiple times across sets of keys, with the -first set to be confirmed becoming the set of keys for that validator set. These -keys remain valid for the validator set until it is changed. If a validator set -remains consistent despite the global validator set updating, their keys carry. -If a validator set adds a new member, and then loses them, their historical keys -are not reused. - -Once new keys are confirmed for a given validator set, they become tracked and -the recommended set of keys for incoming funds. The old keys are still eligible -to receive funds for a provided grace period, requiring the current validator -set to track both sets of keys. The old keys are also still used to handle all -outgoing payments as well, until the end of the grace period, at which point -they're no longer eligible to receive funds and they forward all of their funds -to the new set of keys. - -### `vote(keys: Vec>)` - -Lets a validator vote on a set of keys for their validator set. diff --git a/docs/protocol/Staking.md b/docs/protocol/Staking.md new file mode 100644 index 00000000..f84fb035 --- /dev/null +++ b/docs/protocol/Staking.md @@ -0,0 +1,19 @@ +# Staking + +Serai's staking pallet offers a DPoS system. All stake which enters the system +is delegated somewhere. Delegates can then bond their stake to different +validator sets, justifying their inclusion and providing financial security. + +Delegators may transfer stake whenever, so long as that stake isn't actively +bonded. Delegators may also unstake whenever, so long as the prior condition +is still met. + +### Stake (message) + + - `delegate` (Address): Address to delegate the newly added stake to. + - `amount` (Amount): Amount to stake and delegate. + +### Unstake (message) + + - `delegate` (Address): Address the stake is currently delegated to. + - `amount` (Amount): Amount to unstake. diff --git a/docs/protocol/Validator Sets.md b/docs/protocol/Validator Sets.md index d89510cd..eb6abd7c 100644 --- a/docs/protocol/Validator Sets.md +++ b/docs/protocol/Validator Sets.md @@ -2,29 +2,80 @@ Validator Sets are defined at the protocol level, with the following parameters: - - `index` (VS): Validator set index, a global key atomically increasing -from 0. - - `bond` (Amount): Amount of bond per key-share of this validator set. - - `coins` (Vec\): Coins managed by this validator set. + - `bond` (Amount): Amount of bond per key-share. + - `coins` (Vec\): List of coins within this set. + - `participants` (Vec\): List of participants within this set. -At launch, there will solely be validator set 0, managing Bitcoin, Ethereum, -USDC, DAI, and Monero. +Validator Sets are referred to by `ValidatorSetIndex` yet have their data +accessible via `ValidatorSetInstance`. -### Multisig Management - -Every validator set is expected to form a t-of-n multisig, where n is the amount -of key shares in the validator set and t is `n / 3 * 2 + 1`, per curve required -by its coins. This multisig is secure to hold funds up to 67% of the validator -set's bond value. If funds exceed that threshold, there's more value in the -multisig than in the supermajority of bond that must be put forth to control it. +At launch, there will solely be Validator Set 0, managing Bitcoin, Ether, DAI, +and Monero. ### Participation in the BFT process -All validator sets participate in the BFT process. Specifically, a block -containing `Oraclization`s for a coin must be approved by the BFT majority of -the validator set responsible for it, along with the BFT majority of the network -by bond. +All Validator Sets participate in the BFT process described under +[Consensus](./Consensus.md). Specifically, a block containing In Instructions +for a coin must be approved by the BFT majority of the Validator Set responsible +for it, along with the BFT majority of the network by bond. -At this time, `Oraclization`s for a coin are only expected to be included when a -validator from the validator set managing the coin is the producer of the block +At this time, In Instructions for a coin are only expected to be included when a +validator from the Validator Set managing the coin is the producer of the block in question. + +Since there is currently only one Validator Set, the aforementioned BFT +conditions collapse to simply the BFT majority by bond. Ensuring BFT majority +per responsible Validator Set is accordingly unimplemented for now. + +### Multisig + +Every Validator Set is expected to form a `t`-of-`n` multisig, where `n` is the +amount of key shares in the Validator Set and `t` is `n * 2 / 3 + 1`, for each +of its networks. This multisig is secure to hold coins up to 67% of the +Validator Set's bonded value. If the coins exceed that threshold, there's more +value in the multisig than in the supermajority of bond that must be put forth +to control it. Accordingly, it'd be no longer financially secure, and it MUST +reject newly added coins which would cross that threshold. + +### Multisig Creation + +Multisigs are created by processors, communicating via their Coordinators. +They're then confirmed on chain via the `validator-sets` pallet. This is done by +having 100% of participants agree on the resulting group key. While this isn't +fault tolerant, a malicious actor who forces a `t`-of-`n` multisig to be +`t`-of-`n-1` reduces the fault tolerance of the multisig which is a greater +issue. If a node does prevent multisig creation, other validators should issue +slashes for it/remove it from the Validator Set entirely. + +Due to the fact multiple key generations may occur to account for +faulty/malicious nodes, voting on multiple keys for a single coin is allowed, +with the first key to be confirmed becoming the key for that coin. + +Placing it on chain also solves the question of if the multisig was successfully +created or not. Processors cannot simply ask each other if they succeeded +without creating an instance of the Byzantine Generals Problem. Placing results +within a Byzantine Fault Tolerant system resolves this. + +### Multisig Lifetime + +The keys for a Validator Set remain valid until its participants change. If a +Validator Set adds a new member, and then they leave, the set's historical keys +are not reused. + +### Multisig Handoffs + +Once new keys are confirmed for a given Validator Set, they become tracked and +the recommended set of keys for incoming coins. The old keys are still eligible +to receive coins for a provided grace period, requiring the current Validator +Set to track both sets of keys. The old keys are also prioritized for handling +outbound transfers, until the end of the grace period, at which point they're +no longer eligible to receive coins and they forward all of their coins to the +new set of keys. It is only then that validators in the previous instance of the +set, yet not the current instance, may unbond their stake. + +### Vote (message) + + - `coin` (Coin): Coin whose key is being voted for. + - `key` (Key): Key being voted on. + +Once a key is voted on by every member, it's adopted as detailed above. diff --git a/docs/protocol/Validators.md b/docs/protocol/Validators.md deleted file mode 100644 index c750a1a9..00000000 --- a/docs/protocol/Validators.md +++ /dev/null @@ -1,44 +0,0 @@ -# Validators - -### Register (message) - - - `validator` (signer): Address which will be the validator on Substrate. - - `manager` (signer): Address which will manage this validator. - - `set` (VS): Validator set being joined. - -Marks `validator` as a validator candidate for the specified validator set, -enabling delegation. - -### Delegate (message) - - - `delegator` (signer): Address delegating funds to `validator`. - - `validator` (address): Registered validator being delegated to. - - `amount` (Amount): Amount of funds being delegated to `validator`. - -Delegated funds will be removed from `delegator`'s wallet and moved to -`validator`'s bond. `amount` must be a multiple of the validator set's bond, and -`delegator` must be `validator`'s manager. - -### Undelegate (message) - - - `delegator` (signer): Address removing delegated funds from `validator`. - - `validator` (address): Registered validator no longer being delegated to. - - `amount` (Amount): Amount of funds no longer being delegated to -`validator`. - -`delegator` must be `validator`'s manager, and `amount` must be a multiple of -the validator set's bond. `validator` is scheduled to lose an according amount -of key shares at the next churn, and once they do, the specified amount will be -moved from `validator`'s bond to `delegator`'s wallet. - -`validator`'s bond must be at least the validator set's bond after the -undelegation. - -### Resign (message) - - - `manager` (signer): Manager of `validator`. - - `validator` (address): Validator being removed from the pool/candidacy. - -If `validator` is active, they will be removed at the next churn. If they are -solely a candidate, they will no longer be eligible for delegations. All bond is -refunded after their removal. diff --git a/processor/Cargo.toml b/processor/Cargo.toml index 127d5bd6..3c643db9 100644 --- a/processor/Cargo.toml +++ b/processor/Cargo.toml @@ -14,29 +14,41 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] +# Macros async-trait = "0.1" zeroize = "^1.5" thiserror = "1" rand_core = "0.6" -group = "0.12" - -curve25519-dalek = { version = "3", features = ["std"] } - +# Cryptography transcript = { package = "flexible-transcript", path = "../crypto/transcript", features = ["recommended"] } -dalek-ff-group = { path = "../crypto/dalek-ff-group", features = ["black_box"] } -frost = { package = "modular-frost", path = "../crypto/frost", features = ["ed25519"] } +group = "0.12" +frost = { package = "modular-frost", path = "../crypto/frost", features = ["secp256k1", "ed25519"] } + +# Monero +curve25519-dalek = { version = "3", features = ["std"] } +dalek-ff-group = { path = "../crypto/dalek-ff-group", features = ["black_box"] } monero-serai = { path = "../coins/monero", features = ["multisig"] } +# Bitcoin +bitcoin-serai = { path = "../coins/bitcoin" } + +k256 = { version = "0.12", features = ["arithmetic"] } +bitcoin = "0.29" +hex = "0.4" +secp256k1 = { version = "0.24", features = ["global-context", "rand-std"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + [dev-dependencies] rand_core = "0.6" hex = "0.4" -serde = { version = "1.0", features = ["derive"] } +serde = { version = "1", features = ["derive"] } serde_json = "1.0" futures = "0.3" tokio = { version = "1", features = ["full"] } -frost = { package = "modular-frost", path = "../crypto/frost", features = ["ed25519", "tests"] } +frost = { package = "modular-frost", path = "../crypto/frost", features = ["tests"] } diff --git a/processor/LICENSE b/processor/LICENSE index d6e1814a..c425427c 100644 --- a/processor/LICENSE +++ b/processor/LICENSE @@ -1,6 +1,6 @@ AGPL-3.0-only license -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 as diff --git a/processor/src/coin/bitcoin.rs b/processor/src/coin/bitcoin.rs new file mode 100644 index 00000000..57f925b7 --- /dev/null +++ b/processor/src/coin/bitcoin.rs @@ -0,0 +1,318 @@ +use std::{io, collections::HashMap}; + +use async_trait::async_trait; + +#[rustfmt::skip] +use bitcoin::{ + hashes::Hash, schnorr::TweakedPublicKey, OutPoint, Transaction, Block, Network, Address +}; + +#[cfg(test)] +use bitcoin::{ + secp256k1::{SECP256K1, SecretKey, Message}, + PrivateKey, PublicKey, EcdsaSighashType, + blockdata::script::Builder, + PackedLockTime, Sequence, Script, Witness, TxIn, TxOut, +}; + +use transcript::RecommendedTranscript; +use k256::{ + ProjectivePoint, Scalar, + elliptic_curve::sec1::{ToEncodedPoint, Tag}, +}; +use frost::{curve::Secp256k1, ThresholdKeys}; + +use bitcoin_serai::{ + crypto::{x_only, make_even}, + wallet::{SpendableOutput, TransactionMachine, SignableTransaction as BSignableTransaction}, + rpc::Rpc, +}; + +use crate::coin::{CoinError, Block as BlockTrait, OutputType, Output as OutputTrait, Coin}; + +impl BlockTrait for Block { + type Id = [u8; 32]; + fn id(&self) -> Self::Id { + self.block_hash().as_hash().into_inner() + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Fee(u64); + +#[derive(Clone, Debug)] +pub struct Output(SpendableOutput, OutputType); +impl OutputTrait for Output { + type Id = [u8; 36]; + + fn kind(&self) -> OutputType { + self.1 + } + + fn id(&self) -> Self::Id { + self.0.id() + } + + fn amount(&self) -> u64 { + self.0.output.value + } + + fn serialize(&self) -> Vec { + let mut res = self.0.serialize(); + self.1.write(&mut res).unwrap(); + res + } + + fn read(reader: &mut R) -> io::Result { + Ok(Output(SpendableOutput::read(reader)?, OutputType::read(reader)?)) + } +} + +#[derive(Debug)] +pub struct SignableTransaction { + keys: ThresholdKeys, + transcript: RecommendedTranscript, + actual: BSignableTransaction, +} + +fn next_key(mut key: ProjectivePoint, i: usize) -> (ProjectivePoint, Scalar) { + let mut offset = Scalar::ZERO; + for _ in 0 .. i { + key += ProjectivePoint::GENERATOR; + offset += Scalar::ONE; + + let even_offset; + (key, even_offset) = make_even(key); + offset += Scalar::from(even_offset); + } + (key, offset) +} + +fn branch(key: ProjectivePoint) -> (ProjectivePoint, Scalar) { + next_key(key, 1) +} + +fn change(key: ProjectivePoint) -> (ProjectivePoint, Scalar) { + next_key(key, 2) +} + +#[derive(Clone, Debug)] +pub struct Bitcoin { + pub(crate) rpc: Rpc, +} + +impl Bitcoin { + pub async fn new(url: String) -> Bitcoin { + Bitcoin { rpc: Rpc::new(url) } + } + + #[cfg(test)] + pub async fn fresh_chain(&self) { + if self.rpc.get_latest_block_number().await.unwrap() > 0 { + self + .rpc + .rpc_call("invalidateblock", serde_json::json!([self.rpc.get_block_hash(1).await.unwrap()])) + .await + .unwrap() + } + } +} + +#[async_trait] +impl Coin for Bitcoin { + type Curve = Secp256k1; + + type Fee = Fee; + type Transaction = Transaction; + type Block = Block; + + type Output = Output; + type SignableTransaction = SignableTransaction; + type TransactionMachine = TransactionMachine; + + type Address = Address; + + const ID: &'static [u8] = b"Bitcoin"; + const CONFIRMATIONS: usize = 3; + + // TODO: Get hard numbers and tune + const MAX_INPUTS: usize = 128; + const MAX_OUTPUTS: usize = 16; + + fn tweak_keys(&self, key: &mut ThresholdKeys) { + let (_, offset) = make_even(key.group_key()); + *key = key.offset(Scalar::from(offset)); + } + + fn address(&self, key: ProjectivePoint) -> Self::Address { + debug_assert!(key.to_encoded_point(true).tag() == Tag::CompressedEvenY, "YKey is odd"); + Address::p2tr_tweaked( + TweakedPublicKey::dangerous_assume_tweaked(x_only(&key)), + Network::Regtest, + ) + } + + fn branch_address(&self, key: ProjectivePoint) -> Self::Address { + self.address(branch(key).0) + } + + async fn get_latest_block_number(&self) -> Result { + Ok(self.rpc.get_latest_block_number().await.map_err(|_| CoinError::ConnectionError)?) + } + + async fn get_block(&self, number: usize) -> Result { + let block_hash = + self.rpc.get_block_hash(number).await.map_err(|_| CoinError::ConnectionError)?; + self.rpc.get_block(&block_hash).await.map_err(|_| CoinError::ConnectionError) + } + + async fn get_outputs( + &self, + block: &Self::Block, + key: ProjectivePoint, + ) -> Result, CoinError> { + let external = (key, Scalar::ZERO); + let branch = branch(key); + let change = change(key); + + let entry = + |pair: (_, _), kind| (self.address(pair.0).script_pubkey().to_bytes(), (pair.1, kind)); + let scripts = HashMap::from([ + entry(external, OutputType::External), + entry(branch, OutputType::Branch), + entry(change, OutputType::Change), + ]); + + let mut outputs = Vec::new(); + // Skip the coinbase transaction which is burdened by maturity + for tx in &block.txdata[1 ..] { + for (vout, output) in tx.output.iter().enumerate() { + if let Some(info) = scripts.get(&output.script_pubkey.to_bytes()) { + outputs.push(Output( + SpendableOutput { + offset: info.0, + output: output.clone(), + outpoint: OutPoint { txid: tx.txid(), vout: u32::try_from(vout).unwrap() }, + }, + info.1, + )); + } + } + } + + Ok(outputs) + } + + async fn prepare_send( + &self, + keys: ThresholdKeys, + transcript: RecommendedTranscript, + _: usize, + mut inputs: Vec, + payments: &[(Address, u64)], + change_key: Option, + fee: Fee, + ) -> Result { + Ok(SignableTransaction { + keys, + transcript, + actual: BSignableTransaction::new( + inputs.drain(..).map(|input| input.0).collect(), + payments, + change_key.map(|change_key| self.address(change(change_key).0)), + fee.0, + ) + .ok_or(CoinError::NotEnoughFunds)?, + }) + } + + async fn attempt_send( + &self, + transaction: Self::SignableTransaction, + ) -> Result { + transaction + .actual + .clone() + .multisig(transaction.keys.clone(), transaction.transcript.clone()) + .await + .map_err(|_| CoinError::ConnectionError) + } + + async fn publish_transaction(&self, tx: &Self::Transaction) -> Result, CoinError> { + Ok(self.rpc.send_raw_transaction(tx).await.unwrap().to_vec()) + } + + #[cfg(test)] + async fn get_fee(&self) -> Self::Fee { + Fee(1) + } + + #[cfg(test)] + async fn mine_block(&self) { + self + .rpc + .rpc_call::>( + "generatetoaddress", + serde_json::json!([ + 1, + Address::p2sh(&Script::new(), Network::Regtest).unwrap().to_string() + ]), + ) + .await + .unwrap(); + } + + #[cfg(test)] + async fn test_send(&self, address: Self::Address) { + let secret_key = SecretKey::new(&mut rand_core::OsRng); + let private_key = PrivateKey::new(secret_key, Network::Regtest); + let public_key = PublicKey::from_private_key(SECP256K1, &private_key); + let main_addr = Address::p2pkh(&public_key, Network::Regtest); + + let new_block = self.get_latest_block_number().await.unwrap() + 1; + self + .rpc + .rpc_call::>("generatetoaddress", serde_json::json!([1, main_addr])) + .await + .unwrap(); + + for _ in 0 .. 100 { + self.mine_block().await; + } + + // TODO: Consider grabbing bdk as a dev dependency + let tx = self.get_block(new_block).await.unwrap().txdata.swap_remove(0); + let mut tx = Transaction { + version: 2, + lock_time: PackedLockTime::ZERO, + input: vec![TxIn { + previous_output: OutPoint { txid: tx.txid(), vout: 0 }, + script_sig: Script::default(), + sequence: Sequence(u32::MAX), + witness: Witness::default(), + }], + output: vec![TxOut { + value: tx.output[0].value - 10000, + script_pubkey: address.script_pubkey(), + }], + }; + + let mut der = SECP256K1 + .sign_ecdsa_low_r( + &Message::from( + tx.signature_hash(0, &main_addr.script_pubkey(), EcdsaSighashType::All.to_u32()) + .as_hash(), + ), + &private_key.inner, + ) + .serialize_der() + .to_vec(); + der.push(1); + tx.input[0].script_sig = Builder::new().push_slice(&der).push_key(&public_key).into_script(); + + self.rpc.send_raw_transaction(&tx).await.unwrap(); + for _ in 0 .. Self::CONFIRMATIONS { + self.mine_block().await; + } + } +} diff --git a/processor/src/coin/mod.rs b/processor/src/coin/mod.rs index 136df59b..3a81731e 100644 --- a/processor/src/coin/mod.rs +++ b/processor/src/coin/mod.rs @@ -1,4 +1,4 @@ -use std::marker::Send; +use std::io; use async_trait::async_trait; use thiserror::Error; @@ -10,23 +10,63 @@ use frost::{ sign::PreprocessMachine, }; +pub mod bitcoin; +pub use self::bitcoin::Bitcoin; + pub mod monero; pub use self::monero::Monero; -#[derive(Clone, Error, Debug)] +#[derive(Clone, Copy, Error, Debug)] pub enum CoinError { #[error("failed to connect to coin daemon")] ConnectionError, + #[error("not enough funds")] + NotEnoughFunds, +} + +pub trait Block: Sized + Clone { + type Id: Clone + Copy + AsRef<[u8]>; + fn id(&self) -> Self::Id; +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum OutputType { + External, + Branch, + Change, +} + +impl OutputType { + fn write(&self, writer: &mut W) -> io::Result<()> { + writer.write_all(&[match self { + OutputType::External => 0, + OutputType::Branch => 1, + OutputType::Change => 2, + }]) + } + + fn read(reader: &mut R) -> io::Result { + let mut byte = [0; 1]; + reader.read_exact(&mut byte)?; + Ok(match byte[0] { + 0 => OutputType::External, + 1 => OutputType::Branch, + 2 => OutputType::Change, + _ => Err(io::Error::new(io::ErrorKind::Other, "invalid OutputType"))?, + }) + } } pub trait Output: Sized + Clone { - type Id: AsRef<[u8]>; + type Id: Clone + Copy + AsRef<[u8]>; + + fn kind(&self) -> OutputType; fn id(&self) -> Self::Id; fn amount(&self) -> u64; fn serialize(&self) -> Vec; - fn deserialize(reader: &mut R) -> std::io::Result; + fn read(reader: &mut R) -> std::io::Result; } #[async_trait] @@ -35,7 +75,7 @@ pub trait Coin { type Fee: Copy; type Transaction; - type Block; + type Block: Block; type Output: Output; type SignableTransaction; @@ -48,8 +88,13 @@ pub trait Coin { const MAX_INPUTS: usize; const MAX_OUTPUTS: usize; // TODO: Decide if this includes change or not + fn tweak_keys(&self, key: &mut ThresholdKeys); + + /// Address for the given group key to receive external coins to. // Doesn't have to take self, enables some level of caching which is pleasant fn address(&self, key: ::G) -> Self::Address; + /// Address for the given group key to use for scheduled branches. + fn branch_address(&self, key: ::G) -> Self::Address; async fn get_latest_block_number(&self) -> Result; async fn get_block(&self, number: usize) -> Result; @@ -59,9 +104,7 @@ pub trait Coin { key: ::G, ) -> Result, CoinError>; - // TODO: Remove - async fn is_confirmed(&self, tx: &[u8]) -> Result; - + #[allow(clippy::too_many_arguments)] async fn prepare_send( &self, keys: ThresholdKeys, @@ -69,6 +112,7 @@ pub trait Coin { block_number: usize, inputs: Vec, payments: &[(Self::Address, u64)], + change: Option<::G>, fee: Self::Fee, ) -> Result; @@ -77,10 +121,7 @@ pub trait Coin { transaction: Self::SignableTransaction, ) -> Result; - async fn publish_transaction( - &self, - tx: &Self::Transaction, - ) -> Result<(Vec, Vec<::Id>), CoinError>; + async fn publish_transaction(&self, tx: &Self::Transaction) -> Result, CoinError>; #[cfg(test)] async fn get_fee(&self) -> Self::Fee; diff --git a/processor/src/coin/monero.rs b/processor/src/coin/monero.rs index b1656194..9103c3b0 100644 --- a/processor/src/coin/monero.rs +++ b/processor/src/coin/monero.rs @@ -10,20 +10,29 @@ use frost::{curve::Ed25519, ThresholdKeys}; use monero_serai::{ transaction::Transaction, - block::Block, + block::Block as MBlock, rpc::Rpc, wallet::{ ViewPair, Scanner, - address::{Network, MoneroAddress}, - Fee, SpendableOutput, SignableTransaction as MSignableTransaction, TransactionMachine, + address::{Network, SubaddressIndex, AddressSpec, MoneroAddress}, + Fee, SpendableOutput, Change, SignableTransaction as MSignableTransaction, TransactionMachine, }, }; use crate::{ additional_key, - coin::{CoinError, Output as OutputTrait, Coin}, + coin::{CoinError, Block as BlockTrait, OutputType, Output as OutputTrait, Coin}, }; +#[derive(Clone, Debug)] +pub struct Block([u8; 32], MBlock); +impl BlockTrait for Block { + type Id = [u8; 32]; + fn id(&self) -> Self::Id { + self.0 + } +} + #[derive(Clone, Debug)] pub struct Output(SpendableOutput); impl From for Output { @@ -32,12 +41,25 @@ impl From for Output { } } +const EXTERNAL_SUBADDRESS: Option = SubaddressIndex::new(0, 0); +const BRANCH_SUBADDRESS: Option = SubaddressIndex::new(1, 0); +const CHANGE_SUBADDRESS: Option = SubaddressIndex::new(2, 0); + impl OutputTrait for Output { // While we could use (tx, o), using the key ensures we won't be susceptible to the burning bug. - // While the Monero library offers a variant which allows senders to ensure their TXs have unique - // output keys, Serai can still be targeted using the classic burning bug + // While we already are immune, thanks to using featured address, this doesn't hurt and is + // technically more efficient. type Id = [u8; 32]; + fn kind(&self) -> OutputType { + match self.0.output.metadata.subaddress { + EXTERNAL_SUBADDRESS => OutputType::External, + BRANCH_SUBADDRESS => OutputType::Branch, + CHANGE_SUBADDRESS => OutputType::Change, + _ => panic!("unrecognized address was scanned for"), + } + } + fn id(&self) -> Self::Id { self.0.output.data.key.compress().to_bytes() } @@ -50,8 +72,8 @@ impl OutputTrait for Output { self.0.serialize() } - fn deserialize(reader: &mut R) -> std::io::Result { - SpendableOutput::deserialize(reader).map(Output) + fn read(reader: &mut R) -> std::io::Result { + SpendableOutput::read(reader).map(Output) } } @@ -75,23 +97,43 @@ impl Monero { Monero { rpc: Rpc::new(url).unwrap(), view: Zeroizing::new(additional_key::(0).0) } } - fn scanner(&self, spend: dfg::EdwardsPoint) -> Scanner { - Scanner::from_view(ViewPair::new(spend.0, self.view.clone()), Network::Mainnet, None) + fn view_pair(&self, spend: dfg::EdwardsPoint) -> ViewPair { + ViewPair::new(spend.0, self.view.clone()) } - #[cfg(test)] - fn empty_scanner() -> Scanner { - use group::Group; - Scanner::from_view( - ViewPair::new(*dfg::EdwardsPoint::generator(), Zeroizing::new(Scalar::one())), + fn address_internal( + &self, + spend: dfg::EdwardsPoint, + subaddress: Option, + ) -> MoneroAddress { + self.view_pair(spend).address( Network::Mainnet, - Some(std::collections::HashSet::new()), + AddressSpec::Featured { subaddress, payment_id: None, guaranteed: true }, ) } + fn scanner(&self, spend: dfg::EdwardsPoint) -> Scanner { + let mut scanner = Scanner::from_view(self.view_pair(spend), None); + debug_assert!(EXTERNAL_SUBADDRESS.is_none()); + scanner.register_subaddress(BRANCH_SUBADDRESS.unwrap()); + scanner.register_subaddress(CHANGE_SUBADDRESS.unwrap()); + scanner + } + #[cfg(test)] - fn empty_address() -> MoneroAddress { - Self::empty_scanner().address() + fn test_view_pair() -> ViewPair { + use group::Group; + ViewPair::new(*dfg::EdwardsPoint::generator(), Zeroizing::new(Scalar::one())) + } + + #[cfg(test)] + fn test_scanner() -> Scanner { + Scanner::from_view(Self::test_view_pair(), Some(std::collections::HashSet::new())) + } + + #[cfg(test)] + fn test_address() -> MoneroAddress { + Self::test_view_pair().address(Network::Mainnet, AddressSpec::Standard) } } @@ -120,8 +162,15 @@ impl Coin for Monero { const MAX_INPUTS: usize = 128; const MAX_OUTPUTS: usize = 16; + // Monero doesn't require/benefit from tweaking + fn tweak_keys(&self, _: &mut ThresholdKeys) {} + fn address(&self, key: dfg::EdwardsPoint) -> Self::Address { - self.scanner(key).address() + self.address_internal(key, EXTERNAL_SUBADDRESS) + } + + fn branch_address(&self, key: dfg::EdwardsPoint) -> Self::Address { + self.address_internal(key, BRANCH_SUBADDRESS) } async fn get_latest_block_number(&self) -> Result { @@ -130,7 +179,9 @@ impl Coin for Monero { } async fn get_block(&self, number: usize) -> Result { - self.rpc.get_block(number).await.map_err(|_| CoinError::ConnectionError) + let hash = self.rpc.get_block_hash(number).await.map_err(|_| CoinError::ConnectionError)?; + let block = self.rpc.get_block(hash).await.map_err(|_| CoinError::ConnectionError)?; + Ok(Block(hash, block)) } async fn get_outputs( @@ -138,27 +189,33 @@ impl Coin for Monero { block: &Self::Block, key: dfg::EdwardsPoint, ) -> Result, CoinError> { - Ok( - self - .scanner(key) - .scan(&self.rpc, block) - .await - .map_err(|_| CoinError::ConnectionError)? - .iter() - .flat_map(|outputs| outputs.not_locked()) - .map(Output::from) - .collect(), - ) - } - - async fn is_confirmed(&self, tx: &[u8]) -> Result { - let tx_block_number = self - .rpc - .get_transaction_block_number(tx) + let mut transactions = self + .scanner(key) + .scan(&self.rpc, &block.1) .await .map_err(|_| CoinError::ConnectionError)? - .unwrap_or(usize::MAX); - Ok((self.get_latest_block_number().await?.saturating_sub(tx_block_number) + 1) >= 10) + .iter() + .map(|outputs| outputs.not_locked()) + .collect::>(); + + // This should be pointless as we shouldn't be able to scan for any other subaddress + // This just ensures nothing invalid makes it through + for transaction in transactions.iter_mut() { + *transaction = transaction + .drain(..) + .filter(|output| { + [EXTERNAL_SUBADDRESS, BRANCH_SUBADDRESS, CHANGE_SUBADDRESS] + .contains(&output.output.metadata.subaddress) + }) + .collect(); + } + + Ok( + transactions + .drain(..) + .flat_map(|mut outputs| outputs.drain(..).map(Output::from).collect::>()) + .collect(), + ) } async fn prepare_send( @@ -168,9 +225,9 @@ impl Coin for Monero { block_number: usize, mut inputs: Vec, payments: &[(MoneroAddress, u64)], + change: Option, fee: Fee, ) -> Result { - let spend = keys.group_key(); Ok(SignableTransaction { keys, transcript, @@ -179,7 +236,8 @@ impl Coin for Monero { self.rpc.get_protocol().await.unwrap(), // TODO: Make this deterministic inputs.drain(..).map(|input| input.0).collect(), payments.to_vec(), - Some(self.address(spend)), + change + .map(|change| Change::fingerprintable(self.address_internal(change, CHANGE_SUBADDRESS))), vec![], fee, ) @@ -204,12 +262,9 @@ impl Coin for Monero { .map_err(|_| CoinError::ConnectionError) } - async fn publish_transaction( - &self, - tx: &Self::Transaction, - ) -> Result<(Vec, Vec<::Id>), CoinError> { + async fn publish_transaction(&self, tx: &Self::Transaction) -> Result, CoinError> { self.rpc.publish_transaction(tx).await.map_err(|_| CoinError::ConnectionError)?; - Ok((tx.hash().to_vec(), tx.prefix.outputs.iter().map(|output| output.key.to_bytes()).collect())) + Ok(tx.hash().to_vec()) } #[cfg(test)] @@ -228,7 +283,7 @@ impl Coin for Monero { Some(serde_json::json!({ "method": "generateblocks", "params": { - "wallet_address": Self::empty_address().to_string(), + "wallet_address": Self::test_address().to_string(), "amount_of_blocks": 10 }, })), @@ -249,8 +304,8 @@ impl Coin for Monero { self.mine_block().await; } - let outputs = Self::empty_scanner() - .scan(&self.rpc, &self.rpc.get_block(new_block).await.unwrap()) + let outputs = Self::test_scanner() + .scan(&self.rpc, &self.rpc.get_block_by_number(new_block).await.unwrap()) .await .unwrap() .swap_remove(0) @@ -262,7 +317,7 @@ impl Coin for Monero { self.rpc.get_protocol().await.unwrap(), outputs, vec![(address, amount - fee)], - Some(Self::empty_address()), + Some(Change::new(&Self::test_view_pair(), true)), vec![], self.rpc.get_fee().await.unwrap(), ) diff --git a/processor/src/tests/bitcoin.rs b/processor/src/tests/bitcoin.rs new file mode 100644 index 00000000..dcf3aeed --- /dev/null +++ b/processor/src/tests/bitcoin.rs @@ -0,0 +1,12 @@ +use crate::{ + coin::{Coin, Bitcoin}, + tests::test_send, +}; + +#[tokio::test] +async fn bitcoin() { + let bitcoin = Bitcoin::new("http://serai:seraidex@127.0.0.1:18443".to_string()).await; + bitcoin.fresh_chain().await; + let fee = bitcoin.get_fee().await; + test_send(bitcoin, fee).await; +} diff --git a/processor/src/tests/mod.rs b/processor/src/tests/mod.rs index 36e50f74..81b6e14f 100644 --- a/processor/src/tests/mod.rs +++ b/processor/src/tests/mod.rs @@ -1,120 +1,5 @@ -use std::{ - sync::{Arc, RwLock}, - collections::HashMap, -}; +mod send; +pub(crate) use send::test_send; -use async_trait::async_trait; - -use rand_core::OsRng; - -use frost::Participant; - -use crate::{ - NetworkError, Network, - coin::{Coin, Monero}, - wallet::{WalletKeys, MemCoinDb, Wallet}, -}; - -#[derive(Clone)] -struct LocalNetwork { - i: Participant, - size: u16, - round: usize, - #[allow(clippy::type_complexity)] - rounds: Arc>>>>, -} - -impl LocalNetwork { - fn new(size: u16) -> Vec { - let rounds = Arc::new(RwLock::new(vec![])); - let mut res = vec![]; - for i in 1 ..= size { - res.push(LocalNetwork { - i: Participant::new(i).unwrap(), - size, - round: 0, - rounds: rounds.clone(), - }); - } - res - } -} - -#[async_trait] -impl Network for LocalNetwork { - async fn round(&mut self, data: Vec) -> Result>, NetworkError> { - { - let mut rounds = self.rounds.write().unwrap(); - if rounds.len() == self.round { - rounds.push(HashMap::new()); - } - rounds[self.round].insert(self.i, data); - } - - while { - let read = self.rounds.try_read().unwrap(); - read[self.round].len() != usize::from(self.size) - } { - tokio::task::yield_now().await; - } - - let mut res = self.rounds.try_read().unwrap()[self.round].clone(); - res.remove(&self.i); - self.round += 1; - Ok(res) - } -} - -async fn test_send(coin: C, fee: C::Fee) { - // Mine blocks so there's a confirmed block - coin.mine_block().await; - let latest = coin.get_latest_block_number().await.unwrap(); - - let mut keys = frost::tests::key_gen::<_, C::Curve>(&mut OsRng); - let threshold = keys[&Participant::new(1).unwrap()].params().t(); - let mut networks = LocalNetwork::new(threshold); - - let mut wallets = vec![]; - for i in 1 ..= threshold { - let mut wallet = Wallet::new(MemCoinDb::new(), coin.clone()); - wallet.acknowledge_block(0, latest); - wallet.add_keys(&WalletKeys::new(keys.remove(&Participant::new(i).unwrap()).unwrap(), 0)); - wallets.push(wallet); - } - - // Get the chain to a length where blocks have sufficient confirmations - while (latest + (C::CONFIRMATIONS - 1)) > coin.get_latest_block_number().await.unwrap() { - coin.mine_block().await; - } - - for wallet in wallets.iter_mut() { - // Poll to activate the keys - wallet.poll().await.unwrap(); - } - - coin.test_send(wallets[0].address()).await; - - let mut futures = vec![]; - for (network, wallet) in networks.iter_mut().zip(wallets.iter_mut()) { - wallet.poll().await.unwrap(); - - let latest = coin.get_latest_block_number().await.unwrap(); - wallet.acknowledge_block(1, latest - (C::CONFIRMATIONS - 1)); - let signable = wallet - .prepare_sends(1, vec![(wallet.address(), 10000000000)], fee) - .await - .unwrap() - .1 - .swap_remove(0); - futures.push(wallet.attempt_send(network, signable)); - } - - println!("{:?}", hex::encode(futures::future::join_all(futures).await.swap_remove(0).unwrap().0)); -} - -#[tokio::test] -async fn monero() { - let monero = Monero::new("http://127.0.0.1:18081".to_string()).await; - let fee = monero.get_fee().await; - test_send(monero, fee).await; -} +mod bitcoin; +mod monero; \ No newline at end of file diff --git a/processor/src/tests/monero.rs b/processor/src/tests/monero.rs new file mode 100644 index 00000000..68b8a621 --- /dev/null +++ b/processor/src/tests/monero.rs @@ -0,0 +1,11 @@ +use crate::{ + coin::{Coin, Monero}, + tests::test_send, +}; + +#[tokio::test] +async fn monero() { + let monero = Monero::new("http://127.0.0.1:18081".to_string()).await; + let fee = monero.get_fee().await; + test_send(monero, fee).await; +} diff --git a/processor/src/tests/send.rs b/processor/src/tests/send.rs new file mode 100644 index 00000000..066bed55 --- /dev/null +++ b/processor/src/tests/send.rs @@ -0,0 +1,106 @@ +use std::{ + sync::{Arc, RwLock}, + collections::HashMap, +}; + +use async_trait::async_trait; + +use rand_core::OsRng; + +use crate::{ + NetworkError, Network, + coin::Coin, + wallet::{WalletKeys, MemCoinDb, Wallet}, +}; + +#[derive(Clone)] +struct LocalNetwork { + i: u16, + size: u16, + round: usize, + #[allow(clippy::type_complexity)] + rounds: Arc>>>>, +} + +impl LocalNetwork { + fn new(size: u16) -> Vec { + let rounds = Arc::new(RwLock::new(vec![])); + let mut res = vec![]; + for i in 1 ..= size { + res.push(LocalNetwork { i, size, round: 0, rounds: rounds.clone() }); + } + res + } +} + +#[async_trait] +impl Network for LocalNetwork { + async fn round(&mut self, data: Vec) -> Result>, NetworkError> { + { + let mut rounds = self.rounds.write().unwrap(); + if rounds.len() == self.round { + rounds.push(HashMap::new()); + } + rounds[self.round].insert(self.i, data); + } + + while { + let read = self.rounds.try_read().unwrap(); + read[self.round].len() != usize::from(self.size) + } { + tokio::task::yield_now().await; + } + + let mut res = self.rounds.try_read().unwrap()[self.round].clone(); + res.remove(&self.i); + self.round += 1; + Ok(res) + } +} + +pub async fn test_send(coin: C, fee: C::Fee) { + // Mine blocks so there's a confirmed block + coin.mine_block().await; + let latest = coin.get_latest_block_number().await.unwrap(); + + let mut keys = frost::tests::key_gen::<_, C::Curve>(&mut OsRng); + let threshold = keys[&1].params().t(); + let mut networks = LocalNetwork::new(threshold); + + let mut wallets = vec![]; + for i in 1 ..= threshold { + let mut wallet = Wallet::new(MemCoinDb::new(), coin.clone()); + wallet.acknowledge_block(0, latest); + wallet.add_keys(&WalletKeys::new(keys.remove(&i).unwrap(), 0)); + wallets.push(wallet); + } + + // Get the chain to a length where blocks have sufficient confirmations + while (latest + (C::CONFIRMATIONS - 1)) > coin.get_latest_block_number().await.unwrap() { + coin.mine_block().await; + } + + for wallet in wallets.iter_mut() { + // Poll to activate the keys + wallet.poll().await.unwrap(); + } + + coin.test_send(wallets[0].address()).await; + + let mut futures = vec![]; + for (network, wallet) in networks.iter_mut().zip(wallets.iter_mut()) { + wallet.poll().await.unwrap(); + + let latest = coin.get_latest_block_number().await.unwrap(); + wallet.acknowledge_block(1, latest - (C::CONFIRMATIONS - 1)); + let signable = wallet + .prepare_sends(1, vec![(wallet.address(), 100000000)], fee) + .await + .unwrap() + .1 + .swap_remove(0); + futures.push(wallet.attempt_send(network, signable)); + } + + println!("{:?}", hex::encode(futures::future::join_all(futures).await.swap_remove(0).unwrap())); +} diff --git a/processor/src/wallet.rs b/processor/src/wallet.rs index f117e41c..73a90bb9 100644 --- a/processor/src/wallet.rs +++ b/processor/src/wallet.rs @@ -225,18 +225,16 @@ impl Wallet { } pub fn add_keys(&mut self, keys: &WalletKeys) { - self.pending.push((self.acknowledged_block(keys.creation_block), keys.bind(C::ID))); + let creation_block = keys.creation_block; + let mut keys = keys.bind(C::ID); + self.coin.tweak_keys(&mut keys); + self.pending.push((self.acknowledged_block(creation_block), keys)); } pub fn address(&self) -> C::Address { self.coin.address(self.keys[self.keys.len() - 1].0.group_key()) } - // TODO: Remove - pub async fn is_confirmed(&mut self, tx: &[u8]) -> Result { - self.coin.is_confirmed(tx).await - } - pub async fn poll(&mut self) -> Result<(), CoinError> { if self.coin.get_latest_block_number().await? < (C::CONFIRMATIONS - 1) { return Ok(()); @@ -267,8 +265,7 @@ impl Wallet { .coin .get_outputs(&block, keys.group_key()) .await? - .iter() - .cloned() + .drain(..) .filter(|output| self.db.add_output(output)), ); } @@ -287,7 +284,7 @@ impl Wallet { pub async fn prepare_sends( &mut self, canonical: usize, - payments: Vec<(C::Address, u64)>, + mut payments: Vec<(C::Address, u64)>, fee: C::Fee, ) -> Result<(Vec<(C::Address, u64)>, Vec), CoinError> { if payments.is_empty() { @@ -301,7 +298,6 @@ impl Wallet { // As each payment re-appears, let mut payments = schedule[payment] where the only input is // the source payment // let (mut payments, schedule) = schedule(payments); - let mut payments = payments; let mut txs = vec![]; for (keys, outputs) in self.keys.iter_mut() { @@ -325,7 +321,15 @@ impl Wallet { let tx = self .coin - .prepare_send(keys.clone(), transcript, acknowledged_block, inputs, &outputs, fee) + .prepare_send( + keys.clone(), + transcript, + acknowledged_block, + inputs, + &outputs, + Some(keys.group_key()), + fee, + ) .await?; // self.db.save_tx(tx) // TODO txs.push(tx); @@ -339,7 +343,7 @@ impl Wallet { &mut self, network: &mut N, prepared: C::SignableTransaction, - ) -> Result<(Vec, Vec<::Id>), SignError> { + ) -> Result, SignError> { let attempt = self.coin.attempt_send(prepared).await.map_err(SignError::CoinError)?; let (attempt, commitments) = attempt.preprocess(&mut OsRng); diff --git a/substrate/in-instructions/client/Cargo.toml b/substrate/in-instructions/client/Cargo.toml new file mode 100644 index 00000000..d5cda871 --- /dev/null +++ b/substrate/in-instructions/client/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "in-instructions-client" +version = "0.1.0" +description = "Package In Instructions into inherent transactions" +license = "AGPL-3.0-only" +authors = ["Luke Parker "] +edition = "2021" +publish = false + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +async-trait = "0.1" + +scale = { package = "parity-scale-codec", version = "3", features = ["derive", "max-encoded-len"] } + +jsonrpsee-core = "0.16" +jsonrpsee-http-client = "0.16" + +sp-inherents = { git = "https://github.com/serai-dex/substrate" } + +in-instructions-pallet = { path = "../pallet" } diff --git a/contracts/multisig/LICENSE b/substrate/in-instructions/client/LICENSE similarity index 94% rename from contracts/multisig/LICENSE rename to substrate/in-instructions/client/LICENSE index d6e1814a..c425427c 100644 --- a/contracts/multisig/LICENSE +++ b/substrate/in-instructions/client/LICENSE @@ -1,6 +1,6 @@ AGPL-3.0-only license -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 as diff --git a/substrate/in-instructions/client/src/lib.rs b/substrate/in-instructions/client/src/lib.rs new file mode 100644 index 00000000..1571f999 --- /dev/null +++ b/substrate/in-instructions/client/src/lib.rs @@ -0,0 +1,47 @@ +#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] + +use scale::Decode; + +use jsonrpsee_core::client::ClientT; +use jsonrpsee_http_client::HttpClientBuilder; + +use sp_inherents::{Error, InherentData, InherentIdentifier}; + +use in_instructions_pallet::{INHERENT_IDENTIFIER, Updates, InherentError}; + +pub struct InherentDataProvider; +impl InherentDataProvider { + #[allow(clippy::new_without_default)] // This isn't planned to forever have empty arguments + pub fn new() -> InherentDataProvider { + InherentDataProvider + } +} + +#[async_trait::async_trait] +impl sp_inherents::InherentDataProvider for InherentDataProvider { + async fn provide_inherent_data(&self, inherent_data: &mut InherentData) -> Result<(), Error> { + let updates: Updates = (|| async { + let client = HttpClientBuilder::default().build("http://127.0.0.1:5134")?; + client.request("processor_coinUpdates", Vec::::new()).await + })() + .await + .map_err(|e| { + Error::Application(Box::from(format!("couldn't communicate with processor: {e}"))) + })?; + inherent_data.put_data(INHERENT_IDENTIFIER, &updates)?; + Ok(()) + } + + async fn try_handle_error( + &self, + identifier: &InherentIdentifier, + mut error: &[u8], + ) -> Option> { + if *identifier != INHERENT_IDENTIFIER { + return None; + } + + Some(Err(Error::Application(Box::from(::decode(&mut error).ok()?)))) + } +} diff --git a/substrate/in-instructions/pallet/Cargo.toml b/substrate/in-instructions/pallet/Cargo.toml new file mode 100644 index 00000000..c8c3657d --- /dev/null +++ b/substrate/in-instructions/pallet/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "in-instructions-pallet" +version = "0.1.0" +description = "Execute calls via In Instructions from inherent transactions" +license = "AGPL-3.0-only" +authors = ["Luke Parker "] +edition = "2021" +publish = false + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +thiserror = { version = "1", optional = true } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } + +serde = { version = "1", optional = true } + +sp-std = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-inherents = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } + +frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false } +frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } + +serai-primitives = { path = "../../serai/primitives", default-features = false } +in-instructions-primitives = { path = "../primitives", default-features = false } + +tokens-pallet = { path = "../../tokens/pallet", default-features = false } + +[features] +std = [ + "thiserror", + + "scale/std", + "scale-info/std", + + "serde", + + "sp-std/std", + "sp-inherents/std", + "sp-runtime/std", + + "frame-system/std", + "frame-support/std", + + "serai-primitives/std", + "in-instructions-primitives/std", + + "tokens-pallet/std", +] +default = ["std"] diff --git a/substrate/in-instructions/pallet/LICENSE b/substrate/in-instructions/pallet/LICENSE new file mode 100644 index 00000000..c425427c --- /dev/null +++ b/substrate/in-instructions/pallet/LICENSE @@ -0,0 +1,15 @@ +AGPL-3.0-only license + +Copyright (c) 2022-2023 Luke Parker + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License Version 3 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . diff --git a/substrate/in-instructions/pallet/src/lib.rs b/substrate/in-instructions/pallet/src/lib.rs new file mode 100644 index 00000000..ab48d564 --- /dev/null +++ b/substrate/in-instructions/pallet/src/lib.rs @@ -0,0 +1,263 @@ +#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +use scale::{Encode, Decode}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use sp_std::vec::Vec; +use sp_inherents::{InherentIdentifier, IsFatalError}; + +use sp_runtime::RuntimeDebug; + +use serai_primitives::{BlockNumber, BlockHash, Coin, WithAmount, Balance}; + +pub use in_instructions_primitives as primitives; +use primitives::InInstruction; + +pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"ininstrs"; + +#[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Batch { + pub id: BlockHash, + pub instructions: Vec>, +} + +#[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Update { + // Coin's latest block number + pub block_number: BlockNumber, + pub batches: Vec, +} + +// None if the current block producer isn't operating over this coin or otherwise failed to get +// data +pub type Updates = Vec>; + +#[derive(Clone, Copy, Encode, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Decode, thiserror::Error))] +pub enum InherentError { + #[cfg_attr(feature = "std", error("invalid call"))] + InvalidCall, + #[cfg_attr(feature = "std", error("inherent has {0} updates despite us having {1} coins"))] + InvalidUpdateQuantity(u32, u32), + #[cfg_attr( + feature = "std", + error("inherent for coin {0:?} has block number {1:?} despite us having {2:?}") + )] + UnrecognizedBlockNumber(Coin, BlockNumber, BlockNumber), + #[cfg_attr( + feature = "std", + error("inherent for coin {0:?} has block number {1:?} which doesn't succeed {2:?}") + )] + InvalidBlockNumber(Coin, BlockNumber, BlockNumber), + #[cfg_attr(feature = "std", error("coin {0:?} has {1} more batches than we do"))] + UnrecognizedBatches(Coin, u32), + #[cfg_attr(feature = "std", error("coin {0:?} has a different batch (ID {1:?})"))] + DifferentBatch(Coin, BlockHash), +} + +impl IsFatalError for InherentError { + fn is_fatal_error(&self) -> bool { + match self { + InherentError::InvalidCall | InherentError::InvalidUpdateQuantity(..) => true, + InherentError::UnrecognizedBlockNumber(..) => false, + InherentError::InvalidBlockNumber(..) => true, + InherentError::UnrecognizedBatches(..) => false, + // One of our nodes is definitively wrong. If it's ours (signified by it passing consensus), + // we should panic. If it's theirs, they should be slashed + // Unfortunately, we can't return fatal here to trigger a slash as fatal should only be used + // for undeniable, technical invalidity + // TODO: Code a way in which this still triggers a slash vote + InherentError::DifferentBatch(..) => false, + } + } +} + +fn coin_from_index(index: usize) -> Coin { + // Offset by 1 since Serai is the first coin, yet Serai doesn't have updates + Coin::from(1 + u32::try_from(index).unwrap()) +} + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + use tokens_pallet::{Config as TokensConfig, Pallet as Tokens}; + + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config + TokensConfig { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::event] + #[pallet::generate_deposit(fn deposit_event)] + pub enum Event { + Batch { coin: Coin, id: BlockHash }, + Failure { coin: Coin, id: BlockHash, index: u32 }, + } + + #[pallet::pallet] + #[pallet::generate_store(pub(crate) trait Store)] + pub struct Pallet(PhantomData); + + // Used to only allow one set of updates per block, preventing double updating + #[pallet::storage] + pub(crate) type Once = StorageValue<_, bool, ValueQuery>; + // Latest block number agreed upon for a coin + #[pallet::storage] + #[pallet::getter(fn block_number)] + pub(crate) type BlockNumbers = + StorageMap<_, Blake2_256, Coin, BlockNumber, ValueQuery>; + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_finalize(_: BlockNumberFor) { + Once::::take(); + } + } + + impl Pallet { + fn execute(coin: Coin, instruction: WithAmount) -> Result<(), ()> { + match instruction.data { + InInstruction::Transfer(address) => { + Tokens::::mint(address, Balance { coin, amount: instruction.amount }) + } + _ => panic!("unsupported instruction"), + } + Ok(()) + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight((0, DispatchClass::Operational))] // TODO + pub fn update(origin: OriginFor, mut updates: Updates) -> DispatchResult { + ensure_none(origin)?; + assert!(!Once::::exists()); + Once::::put(true); + + for (coin, update) in updates.iter_mut().enumerate() { + if let Some(update) = update { + let coin = coin_from_index(coin); + BlockNumbers::::insert(coin, update.block_number); + + for batch in update.batches.iter_mut() { + Self::deposit_event(Event::Batch { coin, id: batch.id }); + for (i, instruction) in batch.instructions.drain(..).enumerate() { + if Self::execute(coin, instruction).is_err() { + Self::deposit_event(Event::Failure { + coin, + id: batch.id, + index: u32::try_from(i).unwrap(), + }); + } + } + } + } + } + + Ok(()) + } + } + + #[pallet::inherent] + impl ProvideInherent for Pallet { + type Call = Call; + type Error = InherentError; + const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; + + fn create_inherent(data: &InherentData) -> Option { + data + .get_data::(&INHERENT_IDENTIFIER) + .unwrap() + .map(|updates| Call::update { updates }) + } + + // Assumes that only not yet handled batches are provided as inherent data + fn check_inherent(call: &Self::Call, data: &InherentData) -> Result<(), Self::Error> { + // First unwrap is for the Result of fetching/decoding the Updates + // Second unwrap is for the Option of if they exist + let expected = data.get_data::(&INHERENT_IDENTIFIER).unwrap().unwrap(); + // Match to be exhaustive + let updates = match call { + Call::update { ref updates } => updates, + _ => Err(InherentError::InvalidCall)?, + }; + + // The block producer should've provided one update per coin + // We, an honest node, did provide one update per coin + // Accordingly, we should have the same amount of updates + if updates.len() != expected.len() { + Err(InherentError::InvalidUpdateQuantity( + updates.len().try_into().unwrap(), + expected.len().try_into().unwrap(), + ))?; + } + + // This zip is safe since we verified they're equally sized + // This should be written as coins.zip(updates.iter().zip(&expected)), where coins is the + // validator set's coins + // That'd require having context on the validator set right now which isn't worth pulling in + // right now, when we only have one validator set + for (coin, both) in updates.iter().zip(&expected).enumerate() { + let coin = coin_from_index(coin); + match both { + // Block producer claims there's an update for this coin, as do we + (Some(update), Some(expected)) => { + if update.block_number.0 > expected.block_number.0 { + Err(InherentError::UnrecognizedBlockNumber( + coin, + update.block_number, + expected.block_number, + ))?; + } + + let prev = BlockNumbers::::get(coin); + if update.block_number.0 <= prev.0 { + Err(InherentError::InvalidBlockNumber(coin, update.block_number, prev))?; + } + + if update.batches.len() > expected.batches.len() { + Err(InherentError::UnrecognizedBatches( + coin, + (update.batches.len() - expected.batches.len()).try_into().unwrap(), + ))?; + } + + for (batch, expected) in update.batches.iter().zip(&expected.batches) { + if batch != expected { + Err(InherentError::DifferentBatch(coin, batch.id))?; + } + } + } + + // Block producer claims there's an update for this coin, yet we don't + (Some(update), None) => { + Err(InherentError::UnrecognizedBatches(coin, update.batches.len().try_into().unwrap()))? + } + + // Block producer didn't include update for this coin + (None, _) => (), + }; + } + + Ok(()) + } + + fn is_inherent(_: &Self::Call) -> bool { + true + } + } +} + +pub use pallet::*; diff --git a/substrate/in-instructions/primitives/Cargo.toml b/substrate/in-instructions/primitives/Cargo.toml new file mode 100644 index 00000000..fff968ce --- /dev/null +++ b/substrate/in-instructions/primitives/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "in-instructions-primitives" +version = "0.1.0" +description = "Serai instructions library, enabling encoding and decoding" +license = "MIT" +authors = ["Luke Parker "] +edition = "2021" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } + +serde = { version = "1", features = ["derive"], optional = true } + +serai-primitives = { path = "../../serai/primitives", default-features = false } +tokens-primitives = { path = "../../tokens/primitives", default-features = false } + +[features] +std = ["scale/std", "scale-info/std", "serde", "serai-primitives/std", "tokens-primitives/std"] +default = ["std"] diff --git a/substrate/in-instructions/primitives/LICENSE b/substrate/in-instructions/primitives/LICENSE new file mode 100644 index 00000000..6779f0ec --- /dev/null +++ b/substrate/in-instructions/primitives/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2023 Luke Parker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/substrate/in-instructions/primitives/src/lib.rs b/substrate/in-instructions/primitives/src/lib.rs new file mode 100644 index 00000000..efcb85fa --- /dev/null +++ b/substrate/in-instructions/primitives/src/lib.rs @@ -0,0 +1,41 @@ +#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use serai_primitives::{SeraiAddress, ExternalAddress, Data}; + +mod shorthand; +pub use shorthand::*; + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum Application { + DEX, +} + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ApplicationCall { + application: Application, + data: Data, +} + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum InInstruction { + Transfer(SeraiAddress), + Call(ApplicationCall), +} + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct RefundableInInstruction { + pub origin: Option, + pub instruction: InInstruction, +} diff --git a/substrate/in-instructions/primitives/src/shorthand.rs b/substrate/in-instructions/primitives/src/shorthand.rs new file mode 100644 index 00000000..618787b4 --- /dev/null +++ b/substrate/in-instructions/primitives/src/shorthand.rs @@ -0,0 +1,57 @@ +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use serai_primitives::{Coin, Amount, SeraiAddress, ExternalAddress, Data}; + +use tokens_primitives::OutInstruction; + +use crate::RefundableInInstruction; +#[cfg(feature = "std")] +use crate::InInstruction; + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum Shorthand { + Raw(Data), + Swap { + origin: Option, + coin: Coin, + minimum: Amount, + out: OutInstruction, + }, + AddLiquidity { + origin: Option, + minimum: Amount, + gas: Amount, + address: SeraiAddress, + }, +} + +impl Shorthand { + #[cfg(feature = "std")] + pub fn transfer(origin: Option, address: SeraiAddress) -> Option { + Some(Self::Raw( + Data::new( + (RefundableInInstruction { origin, instruction: InInstruction::Transfer(address) }) + .encode(), + ) + .ok()?, + )) + } +} + +impl TryFrom for RefundableInInstruction { + type Error = &'static str; + fn try_from(shorthand: Shorthand) -> Result { + Ok(match shorthand { + Shorthand::Raw(raw) => { + RefundableInInstruction::decode(&mut raw.data()).map_err(|_| "invalid raw instruction")? + } + Shorthand::Swap { .. } => todo!(), + Shorthand::AddLiquidity { .. } => todo!(), + }) + } +} diff --git a/substrate/node/Cargo.toml b/substrate/node/Cargo.toml index 22dcbbcf..dd51b15c 100644 --- a/substrate/node/Cargo.toml +++ b/substrate/node/Cargo.toml @@ -14,24 +14,24 @@ name = "serai-node" [dependencies] async-trait = "0.1" -log = "0.4" - clap = { version = "4", features = ["derive"] } -jsonrpsee = { version = "0.15", features = ["server"] } + +jsonrpsee = { version = "0.16", features = ["server"] } sp-core = { git = "https://github.com/serai-dex/substrate" } -sp-application-crypto = { git = "https://github.com/serai-dex/substrate" } -sp-keystore = { git = "https://github.com/serai-dex/substrate" } sp-keyring = { git = "https://github.com/serai-dex/substrate" } sp-inherents = { git = "https://github.com/serai-dex/substrate" } -sp-timestamp = { git = "https://github.com/serai-dex/substrate" } sp-runtime = { git = "https://github.com/serai-dex/substrate" } sp-blockchain = { git = "https://github.com/serai-dex/substrate" } sp-api = { git = "https://github.com/serai-dex/substrate" } sp-block-builder = { git = "https://github.com/serai-dex/substrate" } sp-consensus = { git = "https://github.com/serai-dex/substrate" } -sc-keystore = { git = "https://github.com/serai-dex/substrate" } +frame-benchmarking = { git = "https://github.com/serai-dex/substrate" } +frame-benchmarking-cli = { git = "https://github.com/serai-dex/substrate" } + +serai-runtime = { path = "../runtime" } + sc-transaction-pool = { git = "https://github.com/serai-dex/substrate" } sc-transaction-pool-api = { git = "https://github.com/serai-dex/substrate" } sc-basic-authorship = { git = "https://github.com/serai-dex/substrate" } @@ -45,20 +45,13 @@ sc-consensus = { git = "https://github.com/serai-dex/substrate" } sc-telemetry = { git = "https://github.com/serai-dex/substrate" } sc-cli = { git = "https://github.com/serai-dex/substrate" } -frame-system = { git = "https://github.com/serai-dex/substrate" } -frame-benchmarking = { git = "https://github.com/serai-dex/substrate" } -frame-benchmarking-cli = { git = "https://github.com/serai-dex/substrate" } -pallet-transaction-payment = { git = "https://github.com/serai-dex/substrate", default-features = false } - -sc-rpc = { git = "https://github.com/serai-dex/substrate" } sc-rpc-api = { git = "https://github.com/serai-dex/substrate" } substrate-frame-rpc-system = { git = "https://github.com/serai-dex/substrate" } pallet-transaction-payment-rpc = { git = "https://github.com/serai-dex/substrate" } -sp-tendermint = { path = "../tendermint/primitives" } -pallet-tendermint = { path = "../tendermint/pallet", default-features = false } -serai-runtime = { path = "../runtime" } +in-instructions-client = { path = "../in-instructions/client" } + sc-tendermint = { path = "../tendermint/client" } [build-dependencies] @@ -70,5 +63,5 @@ runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", - "serai-runtime/runtime-benchmarks" + "serai-runtime/runtime-benchmarks", ] diff --git a/substrate/node/LICENSE b/substrate/node/LICENSE index d6e1814a..c425427c 100644 --- a/substrate/node/LICENSE +++ b/substrate/node/LICENSE @@ -1,6 +1,6 @@ AGPL-3.0-only license -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 as diff --git a/substrate/node/src/chain_spec.rs b/substrate/node/src/chain_spec.rs index 1d45002f..b440b49e 100644 --- a/substrate/node/src/chain_spec.rs +++ b/substrate/node/src/chain_spec.rs @@ -1,40 +1,58 @@ +use sp_core::Pair as PairTrait; + use sc_service::ChainType; -use sp_core::{Pair as PairTrait, sr25519::Pair}; -use pallet_tendermint::crypto::Public; - use serai_runtime::{ - WASM_BINARY, AccountId, opaque::SessionKeys, GenesisConfig, SystemConfig, BalancesConfig, - SessionConfig, + primitives::*, tokens::primitives::ADDRESS as TOKENS_ADDRESS, tendermint::crypto::Public, + WASM_BINARY, opaque::SessionKeys, GenesisConfig, SystemConfig, BalancesConfig, AssetsConfig, + ValidatorSetsConfig, SessionConfig, }; pub type ChainSpec = sc_service::GenericChainSpec; -fn insecure_pair_from_name(name: &'static str) -> Pair { - Pair::from_string(&format!("//{name}"), None).unwrap() -} - -fn account_id_from_name(name: &'static str) -> AccountId { +fn account_from_name(name: &'static str) -> PublicKey { insecure_pair_from_name(name).public() } fn testnet_genesis( wasm_binary: &[u8], validators: &[&'static str], - endowed_accounts: Vec, + endowed_accounts: Vec, ) -> GenesisConfig { let session_key = |name| { - let key = account_id_from_name(name); + let key = account_from_name(name); (key, key, SessionKeys { tendermint: Public::from(key) }) }; GenesisConfig { system: SystemConfig { code: wasm_binary.to_vec() }, + balances: BalancesConfig { balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), }, transaction_payment: Default::default(), + + assets: AssetsConfig { + assets: [BITCOIN, ETHER, DAI, MONERO] + .iter() + .map(|coin| (*coin, TOKENS_ADDRESS.into(), true, 1)) + .collect(), + metadata: vec![ + (BITCOIN, b"Bitcoin".to_vec(), b"BTC".to_vec(), 8), + // Reduce to 8 decimals to feasibly fit within u64 (instead of its native u256) + (ETHER, b"Ether".to_vec(), b"ETH".to_vec(), 8), + (DAI, b"Dai Stablecoin".to_vec(), b"DAI".to_vec(), 8), + (MONERO, b"Monero".to_vec(), b"XMR".to_vec(), 12), + ], + accounts: vec![], + }, + session: SessionConfig { keys: validators.iter().map(|name| session_key(*name)).collect() }, + validator_sets: ValidatorSetsConfig { + bond: Amount(1_000_000 * 10_u64.pow(8)), + coins: vec![BITCOIN, ETHER, DAI, MONERO], + participants: validators.iter().map(|name| account_from_name(name)).collect(), + }, } } @@ -52,18 +70,18 @@ pub fn development_config() -> Result { wasm_binary, &["Alice"], vec![ - account_id_from_name("Alice"), - account_id_from_name("Bob"), - account_id_from_name("Charlie"), - account_id_from_name("Dave"), - account_id_from_name("Eve"), - account_id_from_name("Ferdie"), - account_id_from_name("Alice//stash"), - account_id_from_name("Bob//stash"), - account_id_from_name("Charlie//stash"), - account_id_from_name("Dave//stash"), - account_id_from_name("Eve//stash"), - account_id_from_name("Ferdie//stash"), + account_from_name("Alice"), + account_from_name("Bob"), + account_from_name("Charlie"), + account_from_name("Dave"), + account_from_name("Eve"), + account_from_name("Ferdie"), + account_from_name("Alice//stash"), + account_from_name("Bob//stash"), + account_from_name("Charlie//stash"), + account_from_name("Dave//stash"), + account_from_name("Eve//stash"), + account_from_name("Ferdie//stash"), ], ) }, @@ -96,18 +114,18 @@ pub fn testnet_config() -> Result { wasm_binary, &["Alice", "Bob", "Charlie"], vec![ - account_id_from_name("Alice"), - account_id_from_name("Bob"), - account_id_from_name("Charlie"), - account_id_from_name("Dave"), - account_id_from_name("Eve"), - account_id_from_name("Ferdie"), - account_id_from_name("Alice//stash"), - account_id_from_name("Bob//stash"), - account_id_from_name("Charlie//stash"), - account_id_from_name("Dave//stash"), - account_id_from_name("Eve//stash"), - account_id_from_name("Ferdie//stash"), + account_from_name("Alice"), + account_from_name("Bob"), + account_from_name("Charlie"), + account_from_name("Dave"), + account_from_name("Eve"), + account_from_name("Ferdie"), + account_from_name("Alice//stash"), + account_from_name("Bob//stash"), + account_from_name("Charlie//stash"), + account_from_name("Dave//stash"), + account_from_name("Eve//stash"), + account_from_name("Ferdie//stash"), ], ) }, diff --git a/substrate/node/src/cli.rs b/substrate/node/src/cli.rs index b5869e30..e8bf2d34 100644 --- a/substrate/node/src/cli.rs +++ b/substrate/node/src/cli.rs @@ -9,6 +9,7 @@ pub struct Cli { pub run: RunCmd, } +#[allow(clippy::large_enum_variant)] #[derive(Debug, clap::Subcommand)] pub enum Subcommand { // Key management CLI utilities diff --git a/substrate/node/src/command.rs b/substrate/node/src/command.rs index 43c67a3f..20cd0e29 100644 --- a/substrate/node/src/command.rs +++ b/substrate/node/src/command.rs @@ -1,9 +1,10 @@ -use sc_service::PartialComponents; -use frame_benchmarking_cli::{ExtrinsicFactory, BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; -use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; - use serai_runtime::Block; +use sc_service::{PruningMode, PartialComponents}; + +use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; +use frame_benchmarking_cli::{ExtrinsicFactory, BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; + use crate::{ chain_spec, cli::{Cli, Subcommand}, @@ -135,7 +136,10 @@ pub fn run() -> sc_cli::Result<()> { cli.create_runner(cmd)?.sync_run(|config| cmd.run::(&config)) } - None => cli.create_runner(&cli.run)?.run_node_until_exit(|config| async { + None => cli.create_runner(&cli.run)?.run_node_until_exit(|mut config| async { + if config.role.is_authority() { + config.state_pruning = Some(PruningMode::ArchiveAll); + } service::new_full(config).await.map_err(sc_cli::Error::Service) }), } diff --git a/substrate/node/src/command_helper.rs b/substrate/node/src/command_helper.rs index d0de95b9..beea5b12 100644 --- a/substrate/node/src/command_helper.rs +++ b/substrate/node/src/command_helper.rs @@ -1,16 +1,19 @@ -use std::{sync::Arc, time::Duration}; +use std::sync::Arc; use sp_core::{Encode, Pair}; use sp_keyring::Sr25519Keyring; -use sp_inherents::{InherentData, InherentDataProvider}; +use sp_inherents::InherentData; use sp_runtime::OpaqueExtrinsic; use sc_cli::Result; use sc_client_api::BlockBackend; -use serai_runtime as runtime; -use runtime::SystemCall; +use serai_runtime::{ + VERSION, BlockHashCount, + system::{self, Call as SystemCall}, + transaction_payment, RuntimeCall, UncheckedExtrinsic, SignedPayload, Runtime, +}; use crate::service::FullClient; @@ -45,35 +48,33 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder { pub fn create_benchmark_extrinsic( client: &FullClient, sender: sp_core::sr25519::Pair, - call: runtime::RuntimeCall, + call: RuntimeCall, nonce: u32, -) -> runtime::UncheckedExtrinsic { +) -> UncheckedExtrinsic { let extra = ( - frame_system::CheckNonZeroSender::::new(), - frame_system::CheckSpecVersion::::new(), - frame_system::CheckTxVersion::::new(), - frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(sp_runtime::generic::Era::mortal( - u64::from( - runtime::BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2), - ), + system::CheckNonZeroSender::::new(), + system::CheckSpecVersion::::new(), + system::CheckTxVersion::::new(), + system::CheckGenesis::::new(), + system::CheckEra::::from(sp_runtime::generic::Era::mortal( + u64::from(BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2)), client.chain_info().best_number.into(), )), - frame_system::CheckNonce::::from(nonce), - frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(0), + system::CheckNonce::::from(nonce), + system::CheckWeight::::new(), + transaction_payment::ChargeTransactionPayment::::from(0), ); - runtime::UncheckedExtrinsic::new_signed( + UncheckedExtrinsic::new_signed( call.clone(), - sender.public(), - runtime::SignedPayload::from_raw( + sender.public().into(), + SignedPayload::from_raw( call, extra.clone(), ( (), - runtime::VERSION.spec_version, - runtime::VERSION.transaction_version, + VERSION.spec_version, + VERSION.transaction_version, client.block_hash(0).ok().flatten().unwrap(), client.chain_info().best_hash, (), @@ -87,9 +88,5 @@ pub fn create_benchmark_extrinsic( } pub fn inherent_benchmark_data() -> Result { - let mut inherent_data = InherentData::new(); - sp_timestamp::InherentDataProvider::new(Duration::from_millis(0).into()) - .provide_inherent_data(&mut inherent_data) - .map_err(|e| format!("creating inherent data: {e:?}"))?; - Ok(inherent_data) + Ok(InherentData::new()) } diff --git a/substrate/node/src/rpc.rs b/substrate/node/src/rpc.rs index 076c8dc2..e0a6c16c 100644 --- a/substrate/node/src/rpc.rs +++ b/substrate/node/src/rpc.rs @@ -3,13 +3,17 @@ use std::sync::Arc; use jsonrpsee::RpcModule; use sp_blockchain::{Error as BlockchainError, HeaderBackend, HeaderMetadata}; -use sc_transaction_pool_api::TransactionPool; use sp_block_builder::BlockBuilder; use sp_api::ProvideRuntimeApi; -pub use sc_rpc_api::DenyUnsafe; +use serai_runtime::{ + primitives::{SubstrateAmount, PublicKey}, + opaque::Block, + Index, +}; -use serai_runtime::{opaque::Block, AccountId, Balance, Index}; +pub use sc_rpc_api::DenyUnsafe; +use sc_transaction_pool_api::TransactionPool; pub struct FullDeps { pub client: Arc, @@ -29,8 +33,8 @@ pub fn create_full< deps: FullDeps, ) -> Result, Box> where - C::Api: substrate_frame_rpc_system::AccountNonceApi - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + C::Api: substrate_frame_rpc_system::AccountNonceApi + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + BlockBuilder, { use substrate_frame_rpc_system::{System, SystemApiServer}; diff --git a/substrate/node/src/service.rs b/substrate/node/src/service.rs index 6179c0e2..24457e29 100644 --- a/substrate/node/src/service.rs +++ b/substrate/node/src/service.rs @@ -11,6 +11,8 @@ use sp_inherents::CreateInherentDataProviders; use sp_consensus::DisableProofRecording; use sp_api::ProvideRuntimeApi; +use in_instructions_client::InherentDataProvider as InstructionsProvider; + use sc_executor::{NativeVersion, NativeExecutionDispatch, NativeElseWasmExecutor}; use sc_transaction_pool::FullPool; use sc_network::NetworkService; @@ -24,7 +26,7 @@ pub(crate) use sc_tendermint::{ TendermintClientMinimal, TendermintValidator, TendermintImport, TendermintAuthority, TendermintSelectChain, import_queue, }; -use serai_runtime::{self, BLOCK_SIZE, TARGET_BLOCK_TIME, opaque::Block, RuntimeApi}; +use serai_runtime::{self as runtime, BLOCK_SIZE, TARGET_BLOCK_TIME, opaque::Block, RuntimeApi}; type FullBackend = sc_service::TFullBackend; pub type FullClient = TFullClient>; @@ -46,7 +48,7 @@ impl NativeExecutionDispatch for ExecutorDispatch { type ExtendHostFunctions = (); fn dispatch(method: &str, data: &[u8]) -> Option> { - serai_runtime::api::dispatch(method, data) + runtime::api::dispatch(method, data) } fn native_version() -> NativeVersion { @@ -57,13 +59,13 @@ impl NativeExecutionDispatch for ExecutorDispatch { pub struct Cidp; #[async_trait::async_trait] impl CreateInherentDataProviders for Cidp { - type InherentDataProviders = (sp_timestamp::InherentDataProvider,); + type InherentDataProviders = (InstructionsProvider,); async fn create_inherent_data_providers( &self, _: ::Hash, _: (), ) -> Result> { - Ok((sp_timestamp::InherentDataProvider::from_system_time(),)) + Ok((InstructionsProvider::new(),)) } } @@ -74,9 +76,9 @@ impl TendermintClientMinimal for TendermintValidatorFirm { // guaranteed not to grow the block? const PROPOSED_BLOCK_SIZE_LIMIT: usize = { BLOCK_SIZE as usize }; // 3 seconds - const BLOCK_PROCESSING_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2 / 1000) as u32 }; + const BLOCK_PROCESSING_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2) as u32 }; // 1 second - const LATENCY_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2 / 3 / 1000) as u32 }; + const LATENCY_TIME_IN_SECONDS: u32 = { (TARGET_BLOCK_TIME / 2 / 3) as u32 }; type Block = Block; type Backend = sc_client_db::Backend; @@ -99,7 +101,7 @@ impl TendermintValidator for TendermintValidatorFirm { pub fn new_partial( config: &Configuration, ) -> Result<(TendermintImport, PartialComponents), ServiceError> { - debug_assert_eq!(TARGET_BLOCK_TIME, 6000); + debug_assert_eq!(TARGET_BLOCK_TIME, 6); if config.keystore_remote.is_some() { return Err(ServiceError::Other("Remote Keystores are not supported".to_string())); @@ -200,7 +202,7 @@ pub async fn new_full(mut config: Configuration) -> Result; pub type Block = generic::Block; @@ -70,8 +84,7 @@ use opaque::SessionKeys; #[sp_version::runtime_version] pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("serai"), - // TODO: "core"? - impl_name: create_runtime_str!("turoctocrab"), + impl_name: create_runtime_str!("core"), authoring_version: 1, // TODO: 1? Do we prefer some level of compatibility or our own path? spec_version: 100, @@ -84,10 +97,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // 1 MB pub const BLOCK_SIZE: u32 = 1024 * 1024; // 6 seconds -pub const TARGET_BLOCK_TIME: u64 = 6000; +pub const TARGET_BLOCK_TIME: u64 = 6; /// Measured in blocks. -pub const MINUTES: BlockNumber = 60_000 / (TARGET_BLOCK_TIME as BlockNumber); +pub const MINUTES: BlockNumber = 60 / (TARGET_BLOCK_TIME as BlockNumber); pub const HOURS: BlockNumber = MINUTES * 60; pub const DAYS: BlockNumber = HOURS * 24; @@ -98,14 +111,6 @@ pub fn native_version() -> NativeVersion { const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -// Unit = the base number of indivisible units for balances -const UNIT: Balance = 1_000_000_000_000; -const MILLIUNIT: Balance = 1_000_000_000; - -const fn deposit(items: u32, bytes: u32) -> Balance { - (items as Balance * UNIT + (bytes as Balance) * (5 * MILLIUNIT / 100)) / 10 -} - parameter_types! { pub const BlockHashCount: BlockNumber = 2400; pub const Version: RuntimeVersion = VERSION; @@ -113,33 +118,53 @@ parameter_types! { pub const SS58Prefix: u8 = 42; // TODO: Remove for Bech32m // 1 MB block size limit - pub BlockLength: frame_system::limits::BlockLength = - frame_system::limits::BlockLength::max_with_normal_ratio(BLOCK_SIZE, NORMAL_DISPATCH_RATIO); - pub BlockWeights: frame_system::limits::BlockWeights = - frame_system::limits::BlockWeights::with_sensible_defaults( - (2u64 * WEIGHT_PER_SECOND).set_proof_size(u64::MAX), + pub BlockLength: system::limits::BlockLength = + system::limits::BlockLength::max_with_normal_ratio(BLOCK_SIZE, NORMAL_DISPATCH_RATIO); + pub BlockWeights: system::limits::BlockWeights = + system::limits::BlockWeights::with_sensible_defaults( + Weight::from_ref_time(2u64 * WEIGHT_REF_TIME_PER_SECOND).set_proof_size(u64::MAX), NORMAL_DISPATCH_RATIO, ); - - pub const DepositPerItem: Balance = deposit(1, 0); - pub const DepositPerByte: Balance = deposit(0, 1); - pub const DeletionQueueDepth: u32 = 128; - // The lazy deletion runs inside on_initialize. - pub DeletionWeightLimit: Weight = BlockWeights::get() - .per_class - .get(DispatchClass::Normal) - .max_total - .unwrap_or(BlockWeights::get().max_block); - pub Schedule: pallet_contracts::Schedule = Default::default(); } -impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; +pub struct CallFilter; +impl Contains for CallFilter { + fn contains(call: &RuntimeCall) -> bool { + if let RuntimeCall::Balances(call) = call { + return matches!(call, balances::Call::transfer { .. } | balances::Call::transfer_all { .. }); + } + + if let RuntimeCall::Assets(call) = call { + return matches!( + call, + assets::Call::approve_transfer { .. } | + assets::Call::cancel_approval { .. } | + assets::Call::transfer { .. } | + assets::Call::transfer_approved { .. } + ); + } + if let RuntimeCall::Tokens(call) = call { + return matches!(call, tokens::Call::burn { .. }); + } + if let RuntimeCall::InInstructions(call) = call { + return matches!(call, in_instructions::Call::update { .. }); + } + + if let RuntimeCall::ValidatorSets(call) = call { + return matches!(call, validator_sets::Call::vote { .. }); + } + + false + } +} + +impl system::Config for Runtime { + type BaseCallFilter = CallFilter; type BlockWeights = BlockWeights; type BlockLength = BlockLength; - type AccountId = AccountId; + type AccountId = PublicKey; type RuntimeCall = RuntimeCall; - type Lookup = IdentityLookup; + type Lookup = AccountLookup; type Index = Index; type BlockNumber = BlockNumber; type Hash = Hash; @@ -156,110 +181,120 @@ impl frame_system::Config for Runtime { type OnKilledAccount = (); type OnSetCode = (); - type AccountData = pallet_balances::AccountData; + type AccountData = balances::AccountData; type SystemWeightInfo = (); type SS58Prefix = SS58Prefix; // TODO: Remove for Bech32m - type MaxConsumers = frame_support::traits::ConstU32<16>; + type MaxConsumers = support::traits::ConstU32<16>; } -impl pallet_randomness_collective_flip::Config for Runtime {} - -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = (); - type MinimumPeriod = ConstU64<{ TARGET_BLOCK_TIME / 2 }>; - type WeightInfo = (); -} - -impl pallet_balances::Config for Runtime { +impl balances::Config for Runtime { type MaxLocks = ConstU32<50>; type MaxReserves = (); type ReserveIdentifier = [u8; 8]; - type Balance = Balance; + type Balance = SubstrateAmount; type RuntimeEvent = RuntimeEvent; type DustRemoval = (); type ExistentialDeposit = ConstU64<500>; type AccountStore = System; - type WeightInfo = pallet_balances::weights::SubstrateWeight; + type WeightInfo = balances::weights::SubstrateWeight; } -impl pallet_transaction_payment::Config for Runtime { +impl transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = CurrencyAdapter; type OperationalFeeMultiplier = ConstU8<5>; - type WeightToFee = IdentityFee; - type LengthToFee = IdentityFee; + type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; type FeeMultiplierUpdate = (); } -impl pallet_contracts::Config for Runtime { - type Time = Timestamp; - type Randomness = RandomnessCollectiveFlip; - type Currency = Balances; +impl assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type RuntimeCall = RuntimeCall; + type Balance = SubstrateAmount; + type Currency = Balances; - type CallFilter = frame_support::traits::Nothing; - type DepositPerItem = DepositPerItem; - type DepositPerByte = DepositPerByte; - type CallStack = [pallet_contracts::Frame; 31]; - type WeightPrice = pallet_transaction_payment::Pallet; - type WeightInfo = pallet_contracts::weights::SubstrateWeight; - type ChainExtension = (); - type DeletionQueueDepth = DeletionQueueDepth; - type DeletionWeightLimit = DeletionWeightLimit; - type Schedule = Schedule; - type AddressGenerator = pallet_contracts::DefaultAddressGenerator; + type AssetId = Coin; + type AssetIdParameter = Coin; + type StringLimit = ConstU32<32>; - type MaxCodeLen = ConstU32<{ 128 * 1024 }>; - type MaxStorageKeyLen = ConstU32<128>; + // Don't allow anyone to create assets + type CreateOrigin = support::traits::AsEnsureOriginWithArg>; + type ForceOrigin = system::EnsureRoot; + + // Don't charge fees nor kill accounts + type RemoveItemsLimit = ConstU32<0>; + type AssetDeposit = ConstU64<0>; + type AssetAccountDeposit = ConstU64<0>; + type MetadataDepositBase = ConstU64<0>; + type MetadataDepositPerByte = ConstU64<0>; + type ApprovalDeposit = ConstU64<0>; + + // Unused hooks + type CallbackHandle = (); + type Freezer = (); + type Extra = (); + + type WeightInfo = assets::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); } -impl pallet_tendermint::Config for Runtime {} +impl tokens::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} + +impl in_instructions::Config for Runtime { + type RuntimeEvent = RuntimeEvent; +} const SESSION_LENGTH: BlockNumber = 5 * DAYS; type Sessions = PeriodicSessions, ConstU32<{ SESSION_LENGTH }>>; pub struct IdentityValidatorIdOf; -impl Convert> for IdentityValidatorIdOf { - fn convert(key: Public) -> Option { +impl Convert> for IdentityValidatorIdOf { + fn convert(key: PublicKey) -> Option { Some(key) } } -impl pallet_session::Config for Runtime { +impl validator_sets::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type ValidatorId = AccountId; +} + +impl session::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ValidatorId = PublicKey; type ValidatorIdOf = IdentityValidatorIdOf; type ShouldEndSession = Sessions; type NextSessionRotation = Sessions; type SessionManager = (); type SessionHandler = ::KeyTypeIdProviders; type Keys = SessionKeys; - type WeightInfo = pallet_session::weights::SubstrateWeight; + type WeightInfo = session::weights::SubstrateWeight; } -pub type Address = AccountId; +impl tendermint::Config for Runtime {} + pub type Header = generic::Header; pub type Block = generic::Block; pub type SignedExtra = ( - frame_system::CheckNonZeroSender, - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - frame_system::CheckWeight, - pallet_transaction_payment::ChargeTransactionPayment, + system::CheckNonZeroSender, + system::CheckSpecVersion, + system::CheckTxVersion, + system::CheckGenesis, + system::CheckEra, + system::CheckNonce, + system::CheckWeight, + transaction_payment::ChargeTransactionPayment, ); pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type SignedPayload = generic::SignedPayload; pub type Executive = frame_executive::Executive< Runtime, Block, - frame_system::ChainContext, + system::ChainContext, Runtime, AllPalletsWithSystem, >; @@ -270,14 +305,19 @@ construct_runtime!( NodeBlock = Block, UncheckedExtrinsic = UncheckedExtrinsic { - System: frame_system, - RandomnessCollectiveFlip: pallet_randomness_collective_flip, - Timestamp: pallet_timestamp, - Balances: pallet_balances, - TransactionPayment: pallet_transaction_payment, - Contracts: pallet_contracts, - Session: pallet_session, - Tendermint: pallet_tendermint, + System: system, + + Balances: balances, + TransactionPayment: transaction_payment, + + Assets: assets, + Tokens: tokens, + InInstructions: in_instructions, + + ValidatorSets: validator_sets, + + Session: session, + Tendermint: tendermint, } ); @@ -289,9 +329,8 @@ extern crate frame_benchmarking; mod benches { define_benchmarks!( [frame_benchmarking, BaselineBench::] - [frame_system, SystemBench::] - [pallet_balances, Balances] - [pallet_timestamp, Timestamp] + [system, SystemBench::] + [balances, Balances] ); } @@ -370,32 +409,41 @@ sp_api::impl_runtime_apis! { Tendermint::session() } - fn validators() -> Vec { - Session::validators() + fn validators() -> Vec { + Session::validators().drain(..).map(Into::into).collect() } } - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(account: AccountId) -> Index { + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: PublicKey) -> Index { System::account_nonce(account) } } impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< Block, - Balance + SubstrateAmount > for Runtime { fn query_info( uxt: ::Extrinsic, len: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { TransactionPayment::query_info(uxt, len) } + fn query_fee_details( uxt: ::Extrinsic, len: u32, - ) -> pallet_transaction_payment::FeeDetails { + ) -> transaction_payment::FeeDetails { TransactionPayment::query_fee_details(uxt, len) } + + fn query_weight_to_fee(weight: Weight) -> SubstrateAmount { + TransactionPayment::weight_to_fee(weight) + } + + fn query_length_to_fee(length: u32) -> SubstrateAmount { + TransactionPayment::length_to_fee(length) + } } } diff --git a/substrate/serai/client/Cargo.toml b/substrate/serai/client/Cargo.toml new file mode 100644 index 00000000..f26f2485 --- /dev/null +++ b/substrate/serai/client/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "serai-client" +version = "0.1.0" +description = "Client library for the Serai network" +license = "AGPL-3.0-only" +repository = "https://github.com/serai-dex/serai/tree/develop/client" +authors = ["Luke Parker "] +keywords = ["serai"] +edition = "2021" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +thiserror = "1" + +scale = { package = "parity-scale-codec", version = "3" } +scale-info = "2" +scale-value = "0.6" + +sp-core = { git = "https://github.com/serai-dex/substrate", version = "7" } + +serai-primitives = { path = "../primitives", version = "0.1" } +serai-runtime = { path = "../../runtime", version = "0.1" } + +subxt = "0.25" + +[dev-dependencies] +lazy_static = "1" + +rand_core = "0.6" + +tokio = "1" + +jsonrpsee-server = "0.16" diff --git a/substrate/serai/client/LICENSE b/substrate/serai/client/LICENSE new file mode 100644 index 00000000..c425427c --- /dev/null +++ b/substrate/serai/client/LICENSE @@ -0,0 +1,15 @@ +AGPL-3.0-only license + +Copyright (c) 2022-2023 Luke Parker + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License Version 3 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . diff --git a/substrate/serai/client/metadata.json b/substrate/serai/client/metadata.json new file mode 100644 index 00000000..e69de29b diff --git a/substrate/serai/client/src/in_instructions.rs b/substrate/serai/client/src/in_instructions.rs new file mode 100644 index 00000000..9187d7a4 --- /dev/null +++ b/substrate/serai/client/src/in_instructions.rs @@ -0,0 +1,37 @@ +use serai_runtime::{in_instructions, InInstructions, Runtime}; +pub use in_instructions::primitives; + +use crate::{ + primitives::{Coin, BlockNumber}, + Serai, SeraiError, scale_value, +}; + +const PALLET: &str = "InInstructions"; + +pub type InInstructionsEvent = in_instructions::Event; + +impl Serai { + pub async fn get_batch_events( + &self, + block: [u8; 32], + ) -> Result, SeraiError> { + self + .events::(block, |event| { + matches!(event, InInstructionsEvent::Batch { .. }) + }) + .await + } + + pub async fn get_coin_block_number( + &self, + coin: Coin, + block: [u8; 32], + ) -> Result { + Ok( + self + .storage(PALLET, "BlockNumbers", Some(vec![scale_value(coin)]), block) + .await? + .unwrap_or(BlockNumber(0)), + ) + } +} diff --git a/substrate/serai/client/src/lib.rs b/substrate/serai/client/src/lib.rs new file mode 100644 index 00000000..00af5352 --- /dev/null +++ b/substrate/serai/client/src/lib.rs @@ -0,0 +1,126 @@ +use thiserror::Error; + +use scale::{Encode, Decode}; +mod scale_value; +pub(crate) use crate::scale_value::{scale_value, scale_composite}; +use ::scale_value::Value; + +use subxt::{ + utils::Encoded, + tx::{Signer, DynamicTxPayload, BaseExtrinsicParams, BaseExtrinsicParamsBuilder, TxClient}, + Config as SubxtConfig, OnlineClient, +}; + +pub use serai_primitives as primitives; +use primitives::{Signature, SeraiAddress}; + +use serai_runtime::{ + system::Config, support::traits::PalletInfo as PalletInfoTrait, PalletInfo, Runtime, +}; + +pub mod tokens; +pub mod in_instructions; + +#[derive(Clone, Copy, PartialEq, Eq, Default, Debug, Encode, Decode)] +pub struct Tip { + #[codec(compact)] + pub tip: u64, +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct SeraiConfig; +impl SubxtConfig for SeraiConfig { + type BlockNumber = ::BlockNumber; + + type Hash = ::Hash; + type Hashing = ::Hashing; + + type Index = ::Index; + type AccountId = ::AccountId; + // TODO: Bech32m + type Address = SeraiAddress; + + type Header = ::Header; + type Signature = Signature; + + type ExtrinsicParams = BaseExtrinsicParams; +} + +#[derive(Clone, Error, Debug)] +pub enum SeraiError { + #[error("failed to connect to serai")] + RpcError, + #[error("serai-client library was intended for a different runtime version")] + InvalidRuntime, +} + +#[derive(Clone)] +pub struct Serai(OnlineClient); + +impl Serai { + pub async fn new(url: &str) -> Result { + Ok(Serai(OnlineClient::::from_url(url).await.map_err(|_| SeraiError::RpcError)?)) + } + + async fn storage( + &self, + pallet: &'static str, + name: &'static str, + keys: Option>, + block: [u8; 32], + ) -> Result, SeraiError> { + let storage = self.0.storage(); + let address = subxt::dynamic::storage(pallet, name, keys.unwrap_or(vec![])); + debug_assert!(storage.validate(&address).is_ok(), "invalid storage address"); + + storage + .fetch(&address, Some(block.into())) + .await + .map_err(|_| SeraiError::RpcError)? + .map(|res| R::decode(&mut res.encoded()).map_err(|_| SeraiError::InvalidRuntime)) + .transpose() + } + + async fn events( + &self, + block: [u8; 32], + filter: impl Fn(&E) -> bool, + ) -> Result, SeraiError> { + let mut res = vec![]; + for event in + self.0.events().at(Some(block.into())).await.map_err(|_| SeraiError::RpcError)?.iter() + { + let event = event.map_err(|_| SeraiError::InvalidRuntime)?; + if PalletInfo::index::

().unwrap() == usize::from(event.pallet_index()) { + let mut with_variant: &[u8] = + &[[event.variant_index()].as_ref(), event.field_bytes()].concat(); + let event = E::decode(&mut with_variant).map_err(|_| SeraiError::InvalidRuntime)?; + if filter(&event) { + res.push(event); + } + } + } + Ok(res) + } + + pub async fn get_latest_block_hash(&self) -> Result<[u8; 32], SeraiError> { + Ok(self.0.rpc().finalized_head().await.map_err(|_| SeraiError::RpcError)?.into()) + } + + pub fn sign>( + &self, + signer: &S, + payload: &DynamicTxPayload<'static>, + nonce: u32, + params: BaseExtrinsicParamsBuilder, + ) -> Result { + TxClient::new(self.0.offline()) + .create_signed_with_nonce(payload, signer, nonce, params) + .map(|tx| Encoded(tx.into_encoded())) + .map_err(|_| SeraiError::InvalidRuntime) + } + + pub async fn publish(&self, tx: &Encoded) -> Result<[u8; 32], SeraiError> { + self.0.rpc().submit_extrinsic(tx).await.map(Into::into).map_err(|_| SeraiError::RpcError) + } +} diff --git a/substrate/serai/client/src/scale_value.rs b/substrate/serai/client/src/scale_value.rs new file mode 100644 index 00000000..0e74b1b2 --- /dev/null +++ b/substrate/serai/client/src/scale_value.rs @@ -0,0 +1,18 @@ +use ::scale::Encode; +use scale_info::{MetaType, TypeInfo, Registry, PortableRegistry}; +use scale_value::{Composite, ValueDef, Value, scale}; + +pub(crate) fn scale_value(value: V) -> Value { + let mut registry = Registry::new(); + let id = registry.register_type(&MetaType::new::()).id(); + let registry = PortableRegistry::from(registry); + scale::decode_as_type(&mut value.encode().as_ref(), id, ®istry).unwrap().remove_context() +} + +pub(crate) fn scale_composite(value: V) -> Composite<()> { + match scale_value(value).value { + ValueDef::Composite(composite) => composite, + ValueDef::Variant(variant) => variant.values, + _ => panic!("not composite"), + } +} diff --git a/substrate/serai/client/src/tokens.rs b/substrate/serai/client/src/tokens.rs new file mode 100644 index 00000000..f77e34e1 --- /dev/null +++ b/substrate/serai/client/src/tokens.rs @@ -0,0 +1,68 @@ +use serai_runtime::{ + primitives::{SeraiAddress, SubstrateAmount, Amount, Coin, Balance}, + assets::{AssetDetails, AssetAccount}, + tokens, Tokens, Runtime, +}; +pub use tokens::primitives; +use primitives::OutInstruction; + +use subxt::tx::{self, DynamicTxPayload}; + +use crate::{Serai, SeraiError, scale_value, scale_composite}; + +const PALLET: &str = "Tokens"; + +pub type TokensEvent = tokens::Event; + +impl Serai { + pub async fn get_mint_events(&self, block: [u8; 32]) -> Result, SeraiError> { + self.events::(block, |event| matches!(event, TokensEvent::Mint { .. })).await + } + + pub async fn get_token_supply(&self, block: [u8; 32], coin: Coin) -> Result { + Ok(Amount( + self + .storage::>( + "Assets", + "Asset", + Some(vec![scale_value(coin)]), + block, + ) + .await? + .map(|token| token.supply) + .unwrap_or(0), + )) + } + + pub async fn get_token_balance( + &self, + block: [u8; 32], + coin: Coin, + address: SeraiAddress, + ) -> Result { + Ok(Amount( + self + .storage::>( + "Assets", + "Account", + Some(vec![scale_value(coin), scale_value(address)]), + block, + ) + .await? + .map(|account| account.balance) + .unwrap_or(0), + )) + } + + pub fn burn(balance: Balance, instruction: OutInstruction) -> DynamicTxPayload<'static> { + tx::dynamic( + PALLET, + "burn", + scale_composite(tokens::Call::::burn { balance, instruction }), + ) + } + + pub async fn get_burn_events(&self, block: [u8; 32]) -> Result, SeraiError> { + self.events::(block, |event| matches!(event, TokensEvent::Burn { .. })).await + } +} diff --git a/substrate/serai/client/tests/burn.rs b/substrate/serai/client/tests/burn.rs new file mode 100644 index 00000000..9e58ed4b --- /dev/null +++ b/substrate/serai/client/tests/burn.rs @@ -0,0 +1,79 @@ +use core::time::Duration; + +use rand_core::{RngCore, OsRng}; + +use sp_core::Pair; +use serai_runtime::in_instructions::{Batch, Update}; + +use tokio::time::sleep; + +use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; + +use serai_client::{ + primitives::{ + BITCOIN, BlockNumber, BlockHash, SeraiAddress, Amount, WithAmount, Balance, Data, + ExternalAddress, insecure_pair_from_name, + }, + in_instructions::primitives::InInstruction, + tokens::{primitives::OutInstruction, TokensEvent}, + Serai, +}; + +mod runner; +use runner::{URL, provide_updates}; + +serai_test!( + async fn burn() { + let coin = BITCOIN; + let mut id = BlockHash([0; 32]); + OsRng.fill_bytes(&mut id.0); + let block_number = BlockNumber(u32::try_from(OsRng.next_u64() >> 32).unwrap()); + + let pair = insecure_pair_from_name("Alice"); + let public = pair.public(); + let address = SeraiAddress::from(public); + + let amount = Amount(OsRng.next_u64()); + let balance = Balance { coin, amount }; + + let mut rand_bytes = vec![0; 32]; + OsRng.fill_bytes(&mut rand_bytes); + let external_address = ExternalAddress::new(rand_bytes).unwrap(); + + let mut rand_bytes = vec![0; 32]; + OsRng.fill_bytes(&mut rand_bytes); + let data = Data::new(rand_bytes).unwrap(); + + let batch = Batch { + id, + instructions: vec![WithAmount { data: InInstruction::Transfer(address), amount }], + }; + let update = Update { block_number, batches: vec![batch] }; + let block = provide_updates(vec![Some(update)]).await; + + let serai = Serai::new(URL).await.unwrap(); + assert_eq!(serai.get_token_balance(block, coin, address).await.unwrap(), amount); + + let out = OutInstruction { address: external_address, data: Some(data) }; + let burn = Serai::burn(balance, out.clone()); + + let signer = PairSigner::new(pair); + serai + .publish(&serai.sign(&signer, &burn, 0, BaseExtrinsicParamsBuilder::new()).unwrap()) + .await + .unwrap(); + + loop { + let block = serai.get_latest_block_hash().await.unwrap(); + let events = serai.get_burn_events(block).await.unwrap(); + if events.is_empty() { + sleep(Duration::from_millis(50)).await; + continue; + } + assert_eq!(events, vec![TokensEvent::Burn { address, balance, instruction: out }]); + assert_eq!(serai.get_token_supply(block, coin).await.unwrap(), Amount(0)); + assert_eq!(serai.get_token_balance(block, coin, address).await.unwrap(), Amount(0)); + break; + } + } +); diff --git a/substrate/serai/client/tests/runner.rs b/substrate/serai/client/tests/runner.rs new file mode 100644 index 00000000..61a56ceb --- /dev/null +++ b/substrate/serai/client/tests/runner.rs @@ -0,0 +1,132 @@ +use core::time::Duration; +use std::sync::Arc; + +use lazy_static::lazy_static; + +use tokio::{sync::Mutex, time::sleep}; + +use serai_runtime::in_instructions::Update; +use serai_client::{primitives::Coin, in_instructions::InInstructionsEvent, Serai}; + +use jsonrpsee_server::RpcModule; + +pub const URL: &str = "ws://127.0.0.1:9944"; + +lazy_static! { + pub static ref SEQUENTIAL: Mutex<()> = Mutex::new(()); +} + +#[allow(dead_code)] +pub async fn provide_updates(updates: Vec>) -> [u8; 32] { + let done = Arc::new(Mutex::new(false)); + let done_clone = done.clone(); + let updates_clone = updates.clone(); + + let mut rpc = RpcModule::new(()); + rpc + .register_async_method("processor_coinUpdates", move |_, _| { + let done_clone = done_clone.clone(); + let updates_clone = updates_clone.clone(); + async move { + // Sleep to prevent a race condition where we submit the inherents for this block and the + // next one, then remove them, making them unverifiable, causing the node to panic for + // being self-malicious + sleep(Duration::from_millis(500)).await; + if !*done_clone.lock().await { + Ok(updates_clone) + } else { + Ok(vec![]) + } + } + }) + .unwrap(); + let _handle = jsonrpsee_server::ServerBuilder::default() + .build("127.0.0.1:5134") + .await + .unwrap() + .start(rpc) + .unwrap(); + + let serai = Serai::new(URL).await.unwrap(); + loop { + let latest = serai.get_latest_block_hash().await.unwrap(); + let mut batches = serai.get_batch_events(latest).await.unwrap(); + if batches.is_empty() { + sleep(Duration::from_millis(50)).await; + continue; + } + *done.lock().await = true; + + for (index, update) in updates.iter().enumerate() { + if let Some(update) = update { + let coin_by_index = Coin(u32::try_from(index).unwrap() + 1); + + for expected in &update.batches { + match batches.swap_remove(0) { + InInstructionsEvent::Batch { coin, id } => { + assert_eq!(coin, coin_by_index); + assert_eq!(expected.id, id); + } + _ => panic!("get_batches returned non-batch"), + } + } + assert_eq!( + serai.get_coin_block_number(coin_by_index, latest).await.unwrap(), + update.block_number + ); + } + } + // This will fail if there were more batch events than expected + assert!(batches.is_empty()); + + return latest; + } +} + +#[macro_export] +macro_rules! serai_test { + ($(async fn $name: ident() $body: block)*) => { + $( + #[tokio::test] + async fn $name() { + let guard = runner::SEQUENTIAL.lock().await; + + // Spawn a fresh Serai node + let mut command = { + use core::time::Duration; + use std::{path::Path, process::Command}; + + let node = { + let this_crate = Path::new(env!("CARGO_MANIFEST_DIR")); + let top_level = this_crate.join("../../../"); + top_level.join("target/debug/serai-node") + }; + + let command = Command::new(node).arg("--dev").spawn().unwrap(); + while Serai::new(URL).await.is_err() { + tokio::time::sleep(Duration::from_secs(1)).await; + } + while Serai::new(URL).await.unwrap().get_latest_block_hash().await.is_err() { + tokio::time::sleep(Duration::from_secs(1)).await; + } + // TODO: https://github.com/serai-dex/serai/247 + if std::env::var("GITHUB_CI") == Ok("true".to_string()) { + tokio::time::sleep(Duration::from_secs(60)).await; + } + command + }; + + let local = tokio::task::LocalSet::new(); + local.run_until(async move { + if let Err(err) = tokio::task::spawn_local(async move { $body }).await { + drop(guard); + let _ = command.kill(); + Err(err).unwrap() + } else { + command.kill().unwrap(); + } + }).await; + } + )* + } +} diff --git a/substrate/serai/client/tests/updates.rs b/substrate/serai/client/tests/updates.rs new file mode 100644 index 00000000..05c30c83 --- /dev/null +++ b/substrate/serai/client/tests/updates.rs @@ -0,0 +1,45 @@ +use rand_core::{RngCore, OsRng}; + +use serai_runtime::in_instructions::{Batch, Update}; + +use serai_client::{ + primitives::{BITCOIN, BlockNumber, BlockHash, SeraiAddress, Amount, WithAmount, Balance}, + tokens::TokensEvent, + in_instructions::{primitives::InInstruction, InInstructionsEvent}, + Serai, +}; + +mod runner; +use runner::{URL, provide_updates}; + +serai_test!( + async fn publish_updates() { + let coin = BITCOIN; + let mut id = BlockHash([0; 32]); + OsRng.fill_bytes(&mut id.0); + let block_number = BlockNumber(u32::try_from(OsRng.next_u64() >> 32).unwrap()); + + let mut address = SeraiAddress::new([0; 32]); + OsRng.fill_bytes(&mut address.0); + let amount = Amount(OsRng.next_u64()); + + let batch = Batch { + id, + instructions: vec![WithAmount { data: InInstruction::Transfer(address), amount }], + }; + let update = Update { block_number, batches: vec![batch] }; + let block = provide_updates(vec![Some(update)]).await; + + let serai = Serai::new(URL).await.unwrap(); + let batches = serai.get_batch_events(block).await.unwrap(); + assert_eq!(batches, vec![InInstructionsEvent::Batch { coin, id }]); + assert_eq!(serai.get_coin_block_number(coin, block).await.unwrap(), block_number); + + assert_eq!( + serai.get_mint_events(block).await.unwrap(), + vec![TokensEvent::Mint { address, balance: Balance { coin, amount } }] + ); + assert_eq!(serai.get_token_supply(block, coin).await.unwrap(), amount); + assert_eq!(serai.get_token_balance(block, coin, address).await.unwrap(), amount); + } +); diff --git a/substrate/serai/primitives/Cargo.toml b/substrate/serai/primitives/Cargo.toml new file mode 100644 index 00000000..303a27b0 --- /dev/null +++ b/substrate/serai/primitives/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "serai-primitives" +version = "0.1.0" +description = "Primitives for the Serai blockchain" +license = "MIT" +repository = "https://github.com/serai-dex/serai/tree/develop/substrate/serai/primitives" +authors = ["Luke Parker "] +edition = "2021" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } + +serde = { version = "1", features = ["derive"], optional = true } + +sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false } +sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } + +[features] +std = ["scale/std", "scale-info/std", "serde", "sp-core/std", "sp-runtime/std"] +default = ["std"] diff --git a/substrate/serai/primitives/LICENSE b/substrate/serai/primitives/LICENSE new file mode 100644 index 00000000..c425427c --- /dev/null +++ b/substrate/serai/primitives/LICENSE @@ -0,0 +1,15 @@ +AGPL-3.0-only license + +Copyright (c) 2022-2023 Luke Parker + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License Version 3 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . diff --git a/substrate/serai/primitives/src/account.rs b/substrate/serai/primitives/src/account.rs new file mode 100644 index 00000000..4fcd2390 --- /dev/null +++ b/substrate/serai/primitives/src/account.rs @@ -0,0 +1,93 @@ +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use sp_core::sr25519::{Public, Signature as RistrettoSignature}; +#[cfg(feature = "std")] +use sp_core::{Pair as PairTrait, sr25519::Pair}; + +use sp_runtime::traits::{LookupError, Lookup, StaticLookup}; + +pub type PublicKey = Public; + +#[derive( + Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct SeraiAddress(pub [u8; 32]); +impl SeraiAddress { + pub fn new(key: [u8; 32]) -> SeraiAddress { + SeraiAddress(key) + } +} + +impl From<[u8; 32]> for SeraiAddress { + fn from(key: [u8; 32]) -> SeraiAddress { + SeraiAddress(key) + } +} + +impl From for SeraiAddress { + fn from(key: PublicKey) -> SeraiAddress { + SeraiAddress(key.0) + } +} + +impl From for PublicKey { + fn from(address: SeraiAddress) -> PublicKey { + PublicKey::from_raw(address.0) + } +} + +#[cfg(feature = "std")] +impl std::fmt::Display for SeraiAddress { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // TODO: Bech32 + write!(f, "{:?}", self.0) + } +} + +#[cfg(feature = "std")] +pub fn insecure_pair_from_name(name: &'static str) -> Pair { + Pair::from_string(&format!("//{name}"), None).unwrap() +} + +pub struct AccountLookup; +impl Lookup for AccountLookup { + type Source = SeraiAddress; + type Target = PublicKey; + fn lookup(&self, source: SeraiAddress) -> Result { + Ok(PublicKey::from_raw(source.0)) + } +} +impl StaticLookup for AccountLookup { + type Source = SeraiAddress; + type Target = PublicKey; + fn lookup(source: SeraiAddress) -> Result { + Ok(source.into()) + } + fn unlookup(source: PublicKey) -> SeraiAddress { + source.into() + } +} + +pub type Signature = RistrettoSignature; + +pub const fn pallet_address(pallet: &'static [u8]) -> SeraiAddress { + let mut address = [0; 32]; + let mut set = false; + // Implement a while loop since we can't use a for loop + let mut i = 0; + while i < pallet.len() { + address[i] = pallet[i]; + if address[i] != 0 { + set = true; + } + i += 1; + } + // Make sure this address isn't the identity point + // Doesn't do address != [0; 32] since that's not const + assert!(set, "address is the identity point"); + SeraiAddress(address) +} diff --git a/substrate/serai/primitives/src/amount.rs b/substrate/serai/primitives/src/amount.rs new file mode 100644 index 00000000..5d1875c5 --- /dev/null +++ b/substrate/serai/primitives/src/amount.rs @@ -0,0 +1,53 @@ +use core::{ + ops::{Add, Sub, Mul}, + fmt::Debug, +}; + +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +/// The type used for amounts within Substrate. +// Distinct from Amount due to Substrate's requirements on this type. +// While Amount could have all the necessary traits implemented, not only are they many, it'd make +// Amount a large type with a variety of misc functions. +// The current type's minimalism sets clear bounds on usage. +pub type SubstrateAmount = u64; +/// The type used for amounts. +#[derive( + Clone, Copy, PartialEq, Eq, PartialOrd, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Amount(pub SubstrateAmount); + +impl Add for Amount { + type Output = Amount; + fn add(self, other: Amount) -> Amount { + // Explicitly use checked_add so even if range checks are disabled, this is still checked + Amount(self.0.checked_add(other.0).unwrap()) + } +} + +impl Sub for Amount { + type Output = Amount; + fn sub(self, other: Amount) -> Amount { + Amount(self.0.checked_sub(other.0).unwrap()) + } +} + +impl Mul for Amount { + type Output = Amount; + fn mul(self, other: Amount) -> Amount { + Amount(self.0.checked_mul(other.0).unwrap()) + } +} + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct WithAmount< + T: Clone + PartialEq + Eq + Debug + Encode + Decode + MaxEncodedLen + TypeInfo, +> { + pub data: T, + pub amount: Amount, +} diff --git a/substrate/serai/primitives/src/balance.rs b/substrate/serai/primitives/src/balance.rs new file mode 100644 index 00000000..7842a213 --- /dev/null +++ b/substrate/serai/primitives/src/balance.rs @@ -0,0 +1,37 @@ +use core::ops::{Add, Sub, Mul}; + +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use crate::{Coin, Amount}; + +/// The type used for balances (a Coin and Balance). +#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Balance { + pub coin: Coin, + pub amount: Amount, +} + +impl Add for Balance { + type Output = Balance; + fn add(self, other: Amount) -> Balance { + Balance { coin: self.coin, amount: self.amount + other } + } +} + +impl Sub for Balance { + type Output = Balance; + fn sub(self, other: Amount) -> Balance { + Balance { coin: self.coin, amount: self.amount - other } + } +} + +impl Mul for Balance { + type Output = Balance; + fn mul(self, other: Amount) -> Balance { + Balance { coin: self.coin, amount: self.amount * other } + } +} diff --git a/substrate/serai/primitives/src/block.rs b/substrate/serai/primitives/src/block.rs new file mode 100644 index 00000000..a31b8a3d --- /dev/null +++ b/substrate/serai/primitives/src/block.rs @@ -0,0 +1,46 @@ +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use sp_core::H256; + +/// The type used to identify block numbers. +// Doesn't re-export tendermint-machine's due to traits. +#[derive( + Clone, Copy, Default, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct BlockNumber(pub u32); +impl From for BlockNumber { + fn from(number: u32) -> BlockNumber { + BlockNumber(number) + } +} + +/// The type used to identify block hashes. +// This may not be universally compatible +// If a block exists with a hash which isn't 32-bytes, it can be hashed into a value with 32-bytes +// This would require the processor to maintain a mapping of 32-byte IDs to actual hashes, which +// would be fine +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct BlockHash(pub [u8; 32]); + +impl AsRef<[u8]> for BlockHash { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl From<[u8; 32]> for BlockHash { + fn from(hash: [u8; 32]) -> BlockHash { + BlockHash(hash) + } +} + +impl From for BlockHash { + fn from(hash: H256) -> BlockHash { + BlockHash(hash.into()) + } +} diff --git a/substrate/serai/primitives/src/coins.rs b/substrate/serai/primitives/src/coins.rs new file mode 100644 index 00000000..6a587df4 --- /dev/null +++ b/substrate/serai/primitives/src/coins.rs @@ -0,0 +1,20 @@ +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +/// The type used to identify coins. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Coin(pub u32); +impl From for Coin { + fn from(coin: u32) -> Coin { + Coin(coin) + } +} + +pub const SERAI: Coin = Coin(0); +pub const BITCOIN: Coin = Coin(1); +pub const ETHER: Coin = Coin(2); +pub const DAI: Coin = Coin(3); +pub const MONERO: Coin = Coin(4); diff --git a/substrate/serai/primitives/src/lib.rs b/substrate/serai/primitives/src/lib.rs new file mode 100644 index 00000000..b77dd249 --- /dev/null +++ b/substrate/serai/primitives/src/lib.rs @@ -0,0 +1,81 @@ +#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use sp_core::{ConstU32, bounded::BoundedVec}; + +mod amount; +pub use amount::*; + +mod block; +pub use block::*; + +mod coins; +pub use coins::*; + +mod balance; +pub use balance::*; + +mod account; +pub use account::*; + +// Monero, our current longest address candidate, has a longest address of featured with payment ID +// 1 (enum) + 1 (flags) + 64 (two keys) + 8 (payment ID) = 74 +pub const MAX_ADDRESS_LEN: u32 = 74; + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ExternalAddress(BoundedVec>); +impl ExternalAddress { + #[cfg(feature = "std")] + pub fn new(address: Vec) -> Result { + Ok(ExternalAddress(address.try_into().map_err(|_| "address length exceeds {MAX_ADDRESS_LEN}")?)) + } + + pub fn address(&self) -> &[u8] { + self.0.as_ref() + } + + #[cfg(feature = "std")] + pub fn consume(self) -> Vec { + self.0.into_inner() + } +} + +impl AsRef<[u8]> for ExternalAddress { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +// Should be enough for a Uniswap v3 call +pub const MAX_DATA_LEN: u32 = 512; +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Data(BoundedVec>); +impl Data { + #[cfg(feature = "std")] + pub fn new(data: Vec) -> Result { + Ok(Data(data.try_into().map_err(|_| "data length exceeds {MAX_DATA_LEN}")?)) + } + + pub fn data(&self) -> &[u8] { + self.0.as_ref() + } + + #[cfg(feature = "std")] + pub fn consume(self) -> Vec { + self.0.into_inner() + } +} + +impl AsRef<[u8]> for Data { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} diff --git a/substrate/tendermint/client/Cargo.toml b/substrate/tendermint/client/Cargo.toml index 0698f633..e78f99bb 100644 --- a/substrate/tendermint/client/Cargo.toml +++ b/substrate/tendermint/client/Cargo.toml @@ -33,8 +33,6 @@ sp-consensus = { git = "https://github.com/serai-dex/substrate" } sp-tendermint = { path = "../primitives" } -sc-transaction-pool = { git = "https://github.com/serai-dex/substrate" } -sc-executor = { git = "https://github.com/serai-dex/substrate" } sc-network-common = { git = "https://github.com/serai-dex/substrate" } sc-network = { git = "https://github.com/serai-dex/substrate" } sc-network-gossip = { git = "https://github.com/serai-dex/substrate" } diff --git a/substrate/tendermint/client/LICENSE b/substrate/tendermint/client/LICENSE index d6e1814a..c425427c 100644 --- a/substrate/tendermint/client/LICENSE +++ b/substrate/tendermint/client/LICENSE @@ -1,6 +1,6 @@ AGPL-3.0-only license -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 as diff --git a/substrate/tendermint/client/src/authority/mod.rs b/substrate/tendermint/client/src/authority/mod.rs index 778f50d4..4181b5ee 100644 --- a/substrate/tendermint/client/src/authority/mod.rs +++ b/substrate/tendermint/client/src/authority/mod.rs @@ -21,9 +21,8 @@ use sp_runtime::{ Digest, }; use sp_blockchain::HeaderBackend; -use sp_api::BlockId; -use sp_consensus::{Error, BlockOrigin, Proposer, Environment}; +use sp_consensus::{Error, BlockOrigin, BlockStatus, Proposer, Environment}; use sc_consensus::import_queue::IncomingBlock; use sc_service::ImportQueue; @@ -87,7 +86,6 @@ async fn get_proposal( env: &Arc>, import: &TendermintImport, header: &::Header, - stub: bool, ) -> T::Block { let proposer = env.lock().await.init(header).await.expect("Failed to create a proposer for the new block"); @@ -96,15 +94,11 @@ async fn get_proposal( .propose( import.inherent_data(*header.parent_hash()).await, Digest::default(), - if stub { - Duration::ZERO - } else { - // The first processing time is to build the block - // The second is for it to be downloaded (assumes a block won't take longer to download - // than it'll take to process) - // The third is for it to actually be processed - Duration::from_secs((T::BLOCK_PROCESSING_TIME_IN_SECONDS / 3).into()) - }, + // The first processing time is to build the block + // The second is for it to be downloaded (assumes a block won't take longer to download + // than it'll take to process) + // The third is for it to actually be processed + Duration::from_secs((T::BLOCK_PROCESSING_TIME_IN_SECONDS / 3).into()), Some(T::PROPOSED_BLOCK_SIZE_LIMIT), ) .await @@ -119,7 +113,7 @@ impl TendermintAuthority { } async fn get_proposal(&self, header: &::Header) -> T::Block { - get_proposal(&self.active.as_ref().unwrap().env, &self.import, header, false).await + get_proposal(&self.active.as_ref().unwrap().env, &self.import, header).await } /// Create and run a new Tendermint Authority, proposing and voting on blocks. @@ -200,9 +194,8 @@ impl TendermintAuthority { }; // Get our first proposal - let proposal = authority - .get_proposal(&import.client.header(BlockId::Hash(last_hash)).unwrap().unwrap()) - .await; + let proposal = + authority.get_proposal(&import.client.header(last_hash).unwrap().unwrap()).await; // Create the gossip network // This has to be spawning the machine, else gossip fails for some reason @@ -265,9 +258,10 @@ impl TendermintAuthority { step.send(( BlockNumber(number), Commit::decode(&mut justifications.get(CONSENSUS_ID).unwrap().as_ref()).unwrap(), - // This will fail if syncing occurs radically faster than machine stepping takes - // TODO: Set true when initial syncing - get_proposal(&env, &import, ¬if.header, false).await + // Creating a proposal will fail if syncing occurs radically faster than machine + // stepping takes + // Don't create proposals when stepping accordingly + None )).await.unwrap(); } else { debug!( @@ -405,7 +399,7 @@ impl Network for TendermintAuthority { let mut queue_write = self.import.queue.write().await; *self.import.importing_block.write().unwrap() = Some(hash); - queue_write.as_mut().unwrap().import_blocks( + queue_write.as_mut().unwrap().service_ref().import_blocks( BlockOrigin::ConsensusBroadcast, // TODO: Use BlockOrigin::Own when it's our block vec![IncomingBlock { hash, @@ -439,10 +433,16 @@ impl Network for TendermintAuthority { &mut self, block: T::Block, commit: Commit>, - ) -> T::Block { + ) -> Option { // Prevent import_block from being called while we run let _lock = self.import.sync_lock.lock().await; + // If we didn't import this block already, return + // If it's a legitimate block, we'll pick it up in the standard sync loop + if self.import.client.block_status(block.hash()).unwrap() != BlockStatus::InChainWithState { + return None; + } + // Check if we already imported this externally if self.import.client.justifications(block.hash()).unwrap().is_some() { debug!(target: "tendermint", "Machine produced a commit after we already synced it"); @@ -489,6 +489,6 @@ impl Network for TendermintAuthority { // Clear any blocks for the previous slot which we were willing to recheck *self.import.recheck.write().unwrap() = HashSet::new(); - self.get_proposal(block.header()).await + Some(self.get_proposal(block.header()).await) } } diff --git a/substrate/tendermint/client/src/block_import.rs b/substrate/tendermint/client/src/block_import.rs index 681fbd8c..84fc8dab 100644 --- a/substrate/tendermint/client/src/block_import.rs +++ b/substrate/tendermint/client/src/block_import.rs @@ -2,7 +2,6 @@ use std::{marker::PhantomData, sync::Arc, collections::HashMap}; use async_trait::async_trait; -use sp_api::BlockId; use sp_runtime::traits::{Header, Block}; use sp_blockchain::{BlockStatus, HeaderBackend, Backend as BlockchainBackend}; use sp_consensus::{Error, CacheKeyId, BlockOrigin, SelectChain}; @@ -15,13 +14,12 @@ use crate::{TendermintValidator, tendermint::TendermintImport}; impl TendermintImport { fn check_already_in_chain(&self, hash: ::Hash) -> bool { - let id = BlockId::Hash(hash); // If it's in chain, with justifications, return it's already on chain // If it's in chain, without justifications, continue the block import process to import its // justifications // This can be triggered if the validators add a block, without justifications, yet the p2p // process then broadcasts it with its justifications - (self.client.status(id).unwrap() == BlockStatus::InChain) && + (self.client.status(hash).unwrap() == BlockStatus::InChain) && self.client.justifications(hash).unwrap().is_some() } } @@ -173,7 +171,7 @@ impl> SelectChain for TendermintSelectChain { .0 .blockchain() // There should always be a finalized block - .header(BlockId::Hash(self.0.blockchain().last_finalized().unwrap())) + .header(self.0.blockchain().last_finalized().unwrap()) // There should not be an error in retrieving it and since it's finalized, it should exist .unwrap() .unwrap(), diff --git a/substrate/tendermint/client/src/tendermint.rs b/substrate/tendermint/client/src/tendermint.rs index 6e1b6f9e..49f21506 100644 --- a/substrate/tendermint/client/src/tendermint.rs +++ b/substrate/tendermint/client/src/tendermint.rs @@ -14,7 +14,7 @@ use sp_runtime::{ }; use sp_inherents::{InherentData, InherentDataProvider, CreateInherentDataProviders}; use sp_blockchain::HeaderBackend; -use sp_api::{BlockId, ProvideRuntimeApi}; +use sp_api::ProvideRuntimeApi; use sp_consensus::Error; use sc_consensus::{ForkChoiceStrategy, BlockImportParams}; @@ -97,7 +97,7 @@ impl TendermintImport { .create_inherent_data_providers(parent, ()) .await { - Ok(providers) => match providers.create_inherent_data() { + Ok(providers) => match providers.create_inherent_data().await { Ok(data) => Some(data), Err(err) => { warn!(target: "tendermint", "Failed to create inherent data: {}", err); @@ -121,7 +121,7 @@ impl TendermintImport { let err = self .client .runtime_api() - .check_inherents(&BlockId::Hash(self.client.info().finalized_hash), block, inherent_data) + .check_inherents(self.client.info().finalized_hash, block, inherent_data) .map_err(|_| Error::Other(BlockError::Fatal.into()))?; if err.ok() { diff --git a/substrate/tendermint/client/src/validators.rs b/substrate/tendermint/client/src/validators.rs index d60f179e..9bd0b338 100644 --- a/substrate/tendermint/client/src/validators.rs +++ b/substrate/tendermint/client/src/validators.rs @@ -11,7 +11,7 @@ use sp_application_crypto::{ use sp_keystore::CryptoStore; use sp_staking::SessionIndex; -use sp_api::{BlockId, ProvideRuntimeApi}; +use sp_api::ProvideRuntimeApi; use sc_client_api::HeaderBackend; @@ -34,8 +34,8 @@ impl TendermintValidatorsStruct { fn from_module(client: &Arc) -> Self { let last = client.info().finalized_hash; let api = client.runtime_api(); - let session = api.current_session(&BlockId::Hash(last)).unwrap(); - let validators = api.validators(&BlockId::Hash(last)).unwrap(); + let session = api.current_session(last).unwrap(); + let validators = api.validators(last).unwrap(); Self { session, @@ -59,8 +59,9 @@ impl Refresh { // If the session has changed, re-create the struct with the data on it fn refresh(&self) { let session = self._refresh.read().unwrap().session; - let current_block = BlockId::Hash(self.client.info().finalized_hash); - if session != self.client.runtime_api().current_session(¤t_block).unwrap() { + if session != + self.client.runtime_api().current_session(self.client.info().finalized_hash).unwrap() + { *self._refresh.write().unwrap() = TendermintValidatorsStruct::from_module::(&self.client); } } diff --git a/substrate/tendermint/machine/Cargo.toml b/substrate/tendermint/machine/Cargo.toml index 4d269a7d..4ba9337d 100644 --- a/substrate/tendermint/machine/Cargo.toml +++ b/substrate/tendermint/machine/Cargo.toml @@ -13,12 +13,12 @@ thiserror = "1" log = "0.4" -parity-scale-codec = { version = "3.2", features = ["derive"] } +parity-scale-codec = { version = "3", features = ["derive"] } futures = "0.3" tokio = { version = "1", features = ["macros", "sync", "time", "rt"] } -sp-runtime = { git = "https://github.com/serai-dex/substrate", version = "6.0.0", optional = true } +sp-runtime = { git = "https://github.com/serai-dex/substrate", version = "7.0.0", optional = true } [features] substrate = ["sp-runtime"] diff --git a/substrate/tendermint/machine/LICENSE b/substrate/tendermint/machine/LICENSE index f05b748b..6779f0ec 100644 --- a/substrate/tendermint/machine/LICENSE +++ b/substrate/tendermint/machine/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/substrate/tendermint/machine/src/block.rs b/substrate/tendermint/machine/src/block.rs index 92923ae9..8136f888 100644 --- a/substrate/tendermint/machine/src/block.rs +++ b/substrate/tendermint/machine/src/block.rs @@ -14,7 +14,7 @@ use crate::{ pub(crate) struct BlockData { pub(crate) number: BlockNumber, pub(crate) validator_id: Option, - pub(crate) proposal: N::Block, + pub(crate) proposal: Option, pub(crate) log: MessageLog, pub(crate) slashes: HashSet, @@ -35,7 +35,7 @@ impl BlockData { weights: Arc, number: BlockNumber, validator_id: Option, - proposal: N::Block, + proposal: Option, ) -> BlockData { BlockData { number, @@ -106,12 +106,8 @@ impl BlockData { // 14-21 if Some(proposer) == self.validator_id { - let (round, block) = if let Some((round, block)) = &self.valid { - (Some(*round), block.clone()) - } else { - (None, self.proposal.clone()) - }; - Some(Data::Proposal(round, block)) + let (round, block) = self.valid.clone().unzip(); + block.or_else(|| self.proposal.clone()).map(|block| Data::Proposal(round, block)) } else { self.round_mut().set_timeout(Step::Propose); None diff --git a/substrate/tendermint/machine/src/ext.rs b/substrate/tendermint/machine/src/ext.rs index daa684c3..f78b3608 100644 --- a/substrate/tendermint/machine/src/ext.rs +++ b/substrate/tendermint/machine/src/ext.rs @@ -270,5 +270,5 @@ pub trait Network: Send + Sync { &mut self, block: Self::Block, commit: Commit, - ) -> Self::Block; + ) -> Option; } diff --git a/substrate/tendermint/machine/src/lib.rs b/substrate/tendermint/machine/src/lib.rs index 487f4cbf..4146dbb5 100644 --- a/substrate/tendermint/machine/src/lib.rs +++ b/substrate/tendermint/machine/src/lib.rs @@ -135,7 +135,8 @@ pub struct TendermintMachine { queue: VecDeque>, msg_recv: mpsc::UnboundedReceiver>, - step_recv: mpsc::UnboundedReceiver<(BlockNumber, Commit, N::Block)>, + #[allow(clippy::type_complexity)] + step_recv: mpsc::UnboundedReceiver<(BlockNumber, Commit, Option)>, block: BlockData, } @@ -143,7 +144,7 @@ pub struct TendermintMachine { pub type StepSender = mpsc::UnboundedSender<( BlockNumber, Commit<::SignatureScheme>, - ::Block, + Option<::Block>, )>; pub type MessageSender = mpsc::UnboundedSender>; @@ -186,7 +187,7 @@ impl TendermintMachine { } // 53-54 - async fn reset(&mut self, end_round: RoundNumber, proposal: N::Block) { + async fn reset(&mut self, end_round: RoundNumber, proposal: Option) { // Ensure we have the end time data for the last round self.block.populate_end_time(end_round); @@ -209,7 +210,11 @@ impl TendermintMachine { self.round(RoundNumber(0), Some(round_end)); } - async fn reset_by_commit(&mut self, commit: Commit, proposal: N::Block) { + async fn reset_by_commit( + &mut self, + commit: Commit, + proposal: Option, + ) { let mut round = self.block.round().number; // If this commit is for a round we don't have, jump up to it while self.block.end_time[&round].canonical() < commit.end_time { @@ -271,7 +276,12 @@ impl TendermintMachine { msg_recv, step_recv, - block: BlockData::new(weights, BlockNumber(last_block.0 + 1), validator_id, proposal), + block: BlockData::new( + weights, + BlockNumber(last_block.0 + 1), + validator_id, + Some(proposal), + ), }; // The end time of the last block is the start time for this one diff --git a/substrate/tendermint/machine/tests/ext.rs b/substrate/tendermint/machine/tests/ext.rs index a02afc12..818f2acd 100644 --- a/substrate/tendermint/machine/tests/ext.rs +++ b/substrate/tendermint/machine/tests/ext.rs @@ -140,11 +140,11 @@ impl Network for TestNetwork { &mut self, block: TestBlock, commit: Commit, - ) -> TestBlock { + ) -> Option { dbg!("Adding ", &block); assert!(block.valid.is_ok()); assert!(self.verify_commit(block.id(), &commit)); - TestBlock { id: (u32::from_le_bytes(block.id) + 1).to_le_bytes(), valid: Ok(()) } + Some(TestBlock { id: (u32::from_le_bytes(block.id) + 1).to_le_bytes(), valid: Ok(()) }) } } diff --git a/substrate/tendermint/pallet/LICENSE b/substrate/tendermint/pallet/LICENSE index d6e1814a..c425427c 100644 --- a/substrate/tendermint/pallet/LICENSE +++ b/substrate/tendermint/pallet/LICENSE @@ -1,6 +1,6 @@ AGPL-3.0-only license -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 as diff --git a/substrate/tendermint/primitives/LICENSE b/substrate/tendermint/primitives/LICENSE index d6e1814a..c425427c 100644 --- a/substrate/tendermint/primitives/LICENSE +++ b/substrate/tendermint/primitives/LICENSE @@ -1,6 +1,6 @@ AGPL-3.0-only license -Copyright (c) 2022 Luke Parker +Copyright (c) 2022-2023 Luke Parker This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 as diff --git a/substrate/tokens/pallet/Cargo.toml b/substrate/tokens/pallet/Cargo.toml new file mode 100644 index 00000000..4f7bb8b7 --- /dev/null +++ b/substrate/tokens/pallet/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "tokens-pallet" +version = "0.1.0" +description = "Mint and burn Serai tokens" +license = "AGPL-3.0-only" +authors = ["Luke Parker "] +edition = "2021" +publish = false + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } + +frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false } +frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } + +pallet-assets = { git = "https://github.com/serai-dex/substrate", default-features = false } + +serai-primitives = { path = "../../serai/primitives", default-features = false } +tokens-primitives = { path = "../primitives", default-features = false } + +[features] +std = [ + "scale/std", + "scale-info/std", + + "frame-system/std", + "frame-support/std", + + "pallet-assets/std", + + "serai-primitives/std", +] +default = ["std"] diff --git a/contracts/extension/LICENSE b/substrate/tokens/pallet/LICENSE similarity index 95% rename from contracts/extension/LICENSE rename to substrate/tokens/pallet/LICENSE index d6e1814a..f684d027 100644 --- a/contracts/extension/LICENSE +++ b/substrate/tokens/pallet/LICENSE @@ -1,6 +1,6 @@ AGPL-3.0-only license -Copyright (c) 2022 Luke Parker +Copyright (c) 2023 Luke Parker This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License Version 3 as diff --git a/substrate/tokens/pallet/src/lib.rs b/substrate/tokens/pallet/src/lib.rs new file mode 100644 index 00000000..5d0a0845 --- /dev/null +++ b/substrate/tokens/pallet/src/lib.rs @@ -0,0 +1,83 @@ +#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +pub use tokens_primitives as primitives; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::{pallet_prelude::*, RawOrigin}; + + use pallet_assets::{Config as AssetsConfig, Pallet as AssetsPallet}; + + use serai_primitives::{SubstrateAmount, Coin, Balance, PublicKey, SeraiAddress, AccountLookup}; + use primitives::{ADDRESS, OutInstruction}; + + use super::*; + + #[pallet::config] + pub trait Config: + frame_system::Config + + AssetsConfig + { + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + } + + #[pallet::event] + #[pallet::generate_deposit(fn deposit_event)] + pub enum Event { + // Mint is technically redundant as the assets pallet has the exact same event already + // Providing our own definition here just helps consolidate code + Mint { address: SeraiAddress, balance: Balance }, + Burn { address: SeraiAddress, balance: Balance, instruction: OutInstruction }, + } + + #[pallet::pallet] + #[pallet::generate_store(pub(crate) trait Store)] + pub struct Pallet(PhantomData); + + impl Pallet { + fn burn_internal( + address: SeraiAddress, + balance: Balance, + instruction: OutInstruction, + ) -> DispatchResult { + AssetsPallet::::burn( + RawOrigin::Signed(ADDRESS.into()).into(), + balance.coin, + address, + balance.amount.0, + )?; + Pallet::::deposit_event(Event::Burn { address, balance, instruction }); + Ok(()) + } + + pub fn mint(address: SeraiAddress, balance: Balance) { + // TODO: Prevent minting when it'd cause an amount exceeding the bond + AssetsPallet::::mint( + RawOrigin::Signed(ADDRESS.into()).into(), + balance.coin, + address, + balance.amount.0, + ) + .unwrap(); + Pallet::::deposit_event(Event::Mint { address, balance }); + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight((0, DispatchClass::Normal))] // TODO + pub fn burn( + origin: OriginFor, + balance: Balance, + instruction: OutInstruction, + ) -> DispatchResult { + Self::burn_internal(ensure_signed(origin)?.into(), balance, instruction) + } + } +} + +pub use pallet::*; diff --git a/substrate/tokens/primitives/Cargo.toml b/substrate/tokens/primitives/Cargo.toml new file mode 100644 index 00000000..155376d6 --- /dev/null +++ b/substrate/tokens/primitives/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "tokens-primitives" +version = "0.1.0" +description = "Serai tokens primitives" +license = "MIT" +authors = ["Luke Parker "] +edition = "2021" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } + +serde = { version = "1", features = ["derive"], optional = true } + +serai-primitives = { path = "../../serai/primitives", default-features = false } + +[dev-dependencies] +sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } + +[features] +std = ["scale/std", "scale-info/std", "serde", "sp-runtime/std", "serai-primitives/std"] +default = ["std"] diff --git a/substrate/tokens/primitives/LICENSE b/substrate/tokens/primitives/LICENSE new file mode 100644 index 00000000..e6bff13c --- /dev/null +++ b/substrate/tokens/primitives/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Luke Parker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/substrate/tokens/primitives/src/lib.rs b/substrate/tokens/primitives/src/lib.rs new file mode 100644 index 00000000..94c62a5a --- /dev/null +++ b/substrate/tokens/primitives/src/lib.rs @@ -0,0 +1,33 @@ +#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; + +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +use serai_primitives::{SeraiAddress, ExternalAddress, Data, pallet_address}; + +pub const ADDRESS: SeraiAddress = pallet_address(b"Tokens"); + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct OutInstruction { + pub address: ExternalAddress, + pub data: Option, +} + +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub enum Destination { + Native(SeraiAddress), + External(OutInstruction), +} + +#[test] +fn address() { + use sp_runtime::traits::TrailingZeroInput; + assert_eq!(ADDRESS, SeraiAddress::decode(&mut TrailingZeroInput::new(b"Tokens")).unwrap()); +} diff --git a/substrate/validator-sets/pallet/Cargo.toml b/substrate/validator-sets/pallet/Cargo.toml new file mode 100644 index 00000000..e5f423e4 --- /dev/null +++ b/substrate/validator-sets/pallet/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "validator-sets-pallet" +version = "0.1.0" +description = "Validator sets pallet" +license = "AGPL-3.0-only" +repository = "https://github.com/serai-dex/serai/tree/develop/substrate/validator-sets/pallet" +authors = ["Luke Parker "] +edition = "2021" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } + +frame-system = { git = "https://github.com/serai-dex/substrate", default-features = false } +frame-support = { git = "https://github.com/serai-dex/substrate", default-features = false } + +serai-primitives = { path = "../../serai/primitives", default-features = false } +validator-sets-primitives = { path = "../primitives", default-features = false } + +[features] +std = [ + "scale/std", + "scale-info/std", + + "frame-system/std", + "frame-support/std", + + "serai-primitives/std", + "validator-sets-primitives/std", +] + +runtime-benchmarks = [ + "frame-system/runtime-benchmarks", + "frame-support/runtime-benchmarks", +] + +default = ["std"] diff --git a/substrate/validator-sets/pallet/LICENSE b/substrate/validator-sets/pallet/LICENSE new file mode 100644 index 00000000..c425427c --- /dev/null +++ b/substrate/validator-sets/pallet/LICENSE @@ -0,0 +1,15 @@ +AGPL-3.0-only license + +Copyright (c) 2022-2023 Luke Parker + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License Version 3 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . diff --git a/substrate/validator-sets/pallet/src/lib.rs b/substrate/validator-sets/pallet/src/lib.rs new file mode 100644 index 00000000..b99fc2f5 --- /dev/null +++ b/substrate/validator-sets/pallet/src/lib.rs @@ -0,0 +1,202 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +#[frame_support::pallet] +pub mod pallet { + use scale::{Encode, Decode}; + use scale_info::TypeInfo; + + use frame_system::pallet_prelude::*; + use frame_support::pallet_prelude::*; + + use serai_primitives::*; + use validator_sets_primitives::*; + + #[pallet::config] + pub trait Config: frame_system::Config + TypeInfo { + type RuntimeEvent: IsType<::RuntimeEvent> + From>; + } + + #[pallet::genesis_config] + #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode)] + pub struct GenesisConfig { + /// Bond requirement to join the initial validator set. + /// Every participant at genesis will automatically be assumed to have this much bond. + /// This bond cannot be withdrawn however as there's no stake behind it. + pub bond: Amount, + /// Coins to spawn the network with in the initial validator set. + pub coins: Vec, + /// List of participants to place in the genesis set. + pub participants: Vec, + } + + #[cfg(feature = "std")] + impl Default for GenesisConfig { + fn default() -> Self { + GenesisConfig { bond: Amount(1), coins: vec![], participants: vec![] } + } + } + + // Max of 16 coins per validator set + // At launch, we'll have BTC, ETH, DAI, and XMR + // In the future, these will be split into separate validator sets, so we're already not + // planning expansion beyond just a few coins per validator set + // The only case which really makes sense for multiple coins in a validator set is: + // 1) The coins are small, easy to run, and make no sense to be in their own set + // In this case, it's still hard to ask validators to run 16 different nodes + // 2) The coins are all on the same network yet there's no DEX on-chain + // In these cases, it'd be hard to find and justify 16 different coins from that single chain + // This could probably be just 8, yet 16 is a hedge for the unforseen + // If necessary, this can be increased with a fork + type MaxCoinsPerSet = ConstU32<16>; + + // Support keys up to 96 bytes (BLS12-381 G2) + const MAX_KEY_LEN: u32 = 96; + type MaxKeyLen = ConstU32; + + #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] + pub struct ValidatorSet { + bond: Amount, + coins: BoundedVec, + + // Participant and their amount bonded to this set + // Limit each set to 100 participants for now + participants: BoundedVec<(T::AccountId, Amount), ConstU32<100>>, + } + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); + + /// The details of a validator set instance. + #[pallet::storage] + #[pallet::getter(fn validator_set)] + pub type ValidatorSets = + StorageMap<_, Twox64Concat, ValidatorSetInstance, ValidatorSet, OptionQuery>; + + type Key = BoundedVec; + + /// The key for a given validator set instance coin. + #[pallet::storage] + #[pallet::getter(fn key)] + pub type Keys = + StorageMap<_, Twox64Concat, (ValidatorSetInstance, Coin), Key, OptionQuery>; + + /// If an account has voted for a specific key or not. Prevents them from voting multiple times. + #[pallet::storage] + #[pallet::getter(fn voted)] + pub type Voted = StorageMap<_, Blake2_128Concat, (T::AccountId, Key), (), OptionQuery>; + + /// How many times a key has been voted for. Once consensus is reached, the keys will be adopted. + #[pallet::storage] + #[pallet::getter(fn vote_count)] + pub type VoteCount = + StorageMap<_, Blake2_128Concat, (ValidatorSetInstance, Coin, Key), u16, ValueQuery>; + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + let mut participants = Vec::new(); + for participant in self.participants.clone() { + participants.push((participant, self.bond)); + } + + ValidatorSets::::set( + ValidatorSetInstance(Session(0), ValidatorSetIndex(0)), + Some(ValidatorSet { + bond: self.bond, + coins: BoundedVec::try_from(self.coins.clone()).unwrap(), + participants: BoundedVec::try_from(participants).unwrap(), + }), + ); + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + Vote { + voter: T::AccountId, + instance: ValidatorSetInstance, + coin: Coin, + key: Key, + // Amount of votes the key now has + votes: u16, + }, + KeyGen { + instance: ValidatorSetInstance, + coin: Coin, + key: Key, + }, + } + + #[pallet::error] + pub enum Error { + /// Validator Set doesn't exist. + NonExistentValidatorSet, + /// Non-validator is voting. + NotValidator, + /// Validator Set already generated keys. + AlreadyGeneratedKeys, + /// Vvalidator has already voted for these keys. + AlreadyVoted, + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(0)] // TODO + pub fn vote( + origin: OriginFor, + index: ValidatorSetIndex, + coin: Coin, + key: Key, + ) -> DispatchResult { + let signer = ensure_signed(origin)?; + // TODO: Do we need to check the key is within the length bounds? + // The docs suggest the BoundedVec will create/write, yet not read, which could be an issue + // if it can be passed in + + // TODO: Get session + let session: Session = Session(0); + + // Confirm a key hasn't been set for this set instance + let instance = ValidatorSetInstance(session, index); + if Keys::::get((instance, coin)).is_some() { + Err(Error::::AlreadyGeneratedKeys)?; + } + + // Confirm the signer is a validator in the set + let set = ValidatorSets::::get(instance).ok_or(Error::::NonExistentValidatorSet)?; + + if set.participants.iter().any(|participant| participant.0 == signer) { + Err(Error::::NotValidator)?; + } + + // Confirm this signer hasn't already voted for these keys + if Voted::::get((&signer, &key)).is_some() { + Err(Error::::AlreadyVoted)?; + } + Voted::::set((&signer, &key), Some(())); + + // Add their vote + let votes = VoteCount::::mutate((instance, coin, &key), |value| { + *value += 1; + *value + }); + + Self::deposit_event(Event::Vote { voter: signer, instance, coin, key: key.clone(), votes }); + + // If we've reached consensus, set the key + if usize::try_from(votes).unwrap() == set.participants.len() { + Keys::::set((instance, coin), Some(key.clone())); + Self::deposit_event(Event::KeyGen { instance, coin, key }); + } + + Ok(()) + } + } + + // TODO: Support session rotation +} + +pub use pallet::*; diff --git a/substrate/validator-sets/primitives/Cargo.toml b/substrate/validator-sets/primitives/Cargo.toml new file mode 100644 index 00000000..e458ae95 --- /dev/null +++ b/substrate/validator-sets/primitives/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "validator-sets-primitives" +version = "0.1.0" +description = "Primitives for validator sets" +license = "MIT" +repository = "https://github.com/serai-dex/serai/tree/develop/substrate/validator-sets/primitives" +authors = ["Luke Parker "] +edition = "2021" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"] } + +serde = { version = "1", features = ["derive"], optional = true } + +[features] +std = ["scale/std", "scale-info/std", "serde"] +default = ["std"] diff --git a/substrate/validator-sets/primitives/LICENSE b/substrate/validator-sets/primitives/LICENSE new file mode 100644 index 00000000..c425427c --- /dev/null +++ b/substrate/validator-sets/primitives/LICENSE @@ -0,0 +1,15 @@ +AGPL-3.0-only license + +Copyright (c) 2022-2023 Luke Parker + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License Version 3 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . diff --git a/substrate/validator-sets/primitives/src/lib.rs b/substrate/validator-sets/primitives/src/lib.rs new file mode 100644 index 00000000..642d2800 --- /dev/null +++ b/substrate/validator-sets/primitives/src/lib.rs @@ -0,0 +1,21 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use scale::{Encode, Decode, MaxEncodedLen}; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Serialize, Deserialize}; + +/// The type used to identify a specific session of validators. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct Session(pub u32); + +/// The type used to identify a validator set. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ValidatorSetIndex(pub u16); + +/// The type used to identify a specific validator set during a specific session. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ValidatorSetInstance(pub Session, pub ValidatorSetIndex);