mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 13:39:25 +00:00
Compare commits
2 Commits
653b0e0bbc
...
2d8f70036a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d8f70036a | ||
|
|
dd95494d9c |
2
.github/workflows/daily-deny.yml
vendored
2
.github/workflows/daily-deny.yml
vendored
@@ -21,4 +21,4 @@ jobs:
|
||||
run: cargo install --locked cargo-deny
|
||||
|
||||
- name: Run cargo deny
|
||||
run: cargo deny -L error --all-features check
|
||||
run: cargo deny -L error --all-features check --hide-inclusion-graph
|
||||
|
||||
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
uses: ./.github/actions/build-dependencies
|
||||
|
||||
- name: Install nightly rust
|
||||
run: rustup toolchain install ${{ steps.nightly.outputs.version }} --profile minimal -t wasm32-unknown-unknown -c clippy
|
||||
run: rustup toolchain install ${{ steps.nightly.outputs.version }} --profile minimal -t wasm32-unknown-unknown -c rust-src -c clippy
|
||||
|
||||
- name: Run Clippy
|
||||
run: cargo +${{ steps.nightly.outputs.version }} clippy --all-features --all-targets -- -D warnings -A clippy::items_after_test_module
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
run: cargo install --locked cargo-deny
|
||||
|
||||
- name: Run cargo deny
|
||||
run: cargo deny -L error --all-features check
|
||||
run: cargo deny -L error --all-features check --hide-inclusion-graph
|
||||
|
||||
fmt:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
242
Cargo.lock
generated
242
Cargo.lock
generated
@@ -1052,7 +1052,7 @@ dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.12.1",
|
||||
"itertools 0.10.5",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"proc-macro2",
|
||||
@@ -2685,7 +2685,7 @@ checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
||||
[[package]]
|
||||
name = "fork-tree"
|
||||
version = "13.0.1"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
]
|
||||
@@ -2718,7 +2718,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
|
||||
[[package]]
|
||||
name = "frame-benchmarking"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"frame-support-procedural",
|
||||
@@ -2742,7 +2742,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "frame-executive"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
@@ -2771,7 +2771,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "frame-support"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"bitflags 1.3.2",
|
||||
@@ -2806,7 +2806,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "frame-support-procedural"
|
||||
version = "31.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"cfg-expr",
|
||||
@@ -2825,7 +2825,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "frame-support-procedural-tools"
|
||||
version = "13.0.1"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-support-procedural-tools-derive",
|
||||
"proc-macro-crate 3.2.0",
|
||||
@@ -2837,7 +2837,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "frame-support-procedural-tools-derive"
|
||||
version = "12.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2847,7 +2847,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "frame-system"
|
||||
version = "39.1.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"frame-support",
|
||||
@@ -2866,7 +2866,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "frame-system-rpc-runtime-api"
|
||||
version = "35.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"sp-api",
|
||||
@@ -2875,7 +2875,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "frame-try-runtime"
|
||||
version = "0.45.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"parity-scale-codec",
|
||||
@@ -5618,7 +5618,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pallet-authorship"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
@@ -5631,7 +5631,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pallet-babe"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
@@ -5654,7 +5654,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pallet-grandpa"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
@@ -5676,7 +5676,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pallet-session"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
@@ -5697,7 +5697,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pallet-timestamp"
|
||||
version = "38.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
@@ -5715,7 +5715,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pallet-transaction-payment"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
@@ -5731,7 +5731,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pallet-transaction-payment-rpc"
|
||||
version = "42.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"jsonrpsee",
|
||||
"pallet-transaction-payment-rpc-runtime-api",
|
||||
@@ -5747,7 +5747,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pallet-transaction-payment-rpc-runtime-api"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"pallet-transaction-payment",
|
||||
"parity-scale-codec",
|
||||
@@ -6306,7 +6306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0f3e5beed80eb580c68e2c600937ac2c4eedabdfd5ef1e5b7ea4f3fba84497b"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"itertools 0.13.0",
|
||||
"itertools 0.10.5",
|
||||
"log",
|
||||
"multimap",
|
||||
"once_cell",
|
||||
@@ -6326,7 +6326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157c5a9d7ea5c2ed2d9fb8f495b64759f7816c7eaea54ba3978f0d63000162e3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.13.0",
|
||||
"itertools 0.10.5",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
@@ -7076,7 +7076,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-allocator"
|
||||
version = "30.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"log",
|
||||
"sp-core",
|
||||
@@ -7087,7 +7087,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-authority-discovery"
|
||||
version = "0.48.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -7117,7 +7117,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-basic-authorship"
|
||||
version = "0.48.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"futures-timer",
|
||||
@@ -7139,7 +7139,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-block-builder"
|
||||
version = "0.43.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"sp-api",
|
||||
@@ -7154,7 +7154,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-chain-spec"
|
||||
version = "41.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"log",
|
||||
@@ -7180,7 +7180,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-chain-spec-derive"
|
||||
version = "12.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"proc-macro-crate 3.2.0",
|
||||
"proc-macro2",
|
||||
@@ -7191,7 +7191,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-cli"
|
||||
version = "0.50.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"chrono",
|
||||
@@ -7232,7 +7232,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-client-api"
|
||||
version = "38.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"futures",
|
||||
@@ -7258,7 +7258,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-client-db"
|
||||
version = "0.45.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"hash-db",
|
||||
"kvdb",
|
||||
@@ -7284,7 +7284,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-consensus"
|
||||
version = "0.47.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -7308,7 +7308,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-consensus-babe"
|
||||
version = "0.48.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"fork-tree",
|
||||
@@ -7344,7 +7344,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-consensus-epochs"
|
||||
version = "0.47.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"fork-tree",
|
||||
"parity-scale-codec",
|
||||
@@ -7357,7 +7357,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-consensus-grandpa"
|
||||
version = "0.33.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"array-bytes",
|
||||
@@ -7401,7 +7401,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-consensus-slots"
|
||||
version = "0.47.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -7424,7 +7424,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-executor"
|
||||
version = "0.41.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"parking_lot 0.12.3",
|
||||
@@ -7446,7 +7446,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-executor-common"
|
||||
version = "0.36.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"sc-allocator",
|
||||
"sp-maybe-compressed-blob",
|
||||
@@ -7458,7 +7458,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-executor-wasmtime"
|
||||
version = "0.36.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"log",
|
||||
@@ -7474,7 +7474,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-informant"
|
||||
version = "0.47.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"console",
|
||||
"futures",
|
||||
@@ -7491,7 +7491,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-keystore"
|
||||
version = "34.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"parking_lot 0.12.3",
|
||||
@@ -7505,7 +7505,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-network"
|
||||
version = "0.48.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"async-channel",
|
||||
@@ -7551,7 +7551,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-network-common"
|
||||
version = "0.47.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"parity-scale-codec",
|
||||
@@ -7562,7 +7562,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-network-gossip"
|
||||
version = "0.48.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"futures",
|
||||
@@ -7581,7 +7581,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-network-light"
|
||||
version = "0.47.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"async-channel",
|
||||
@@ -7602,7 +7602,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-network-sync"
|
||||
version = "0.47.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"async-channel",
|
||||
@@ -7637,7 +7637,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-network-transactions"
|
||||
version = "0.47.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"futures",
|
||||
@@ -7656,7 +7656,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-network-types"
|
||||
version = "0.15.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"ed25519-dalek",
|
||||
@@ -7674,7 +7674,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-offchain"
|
||||
version = "43.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"num_cpus",
|
||||
@@ -7698,7 +7698,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-proposer-metrics"
|
||||
version = "0.18.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"log",
|
||||
"substrate-prometheus-endpoint",
|
||||
@@ -7707,7 +7707,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-rpc"
|
||||
version = "43.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"jsonrpsee",
|
||||
@@ -7737,7 +7737,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-rpc-api"
|
||||
version = "0.47.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"jsonrpsee",
|
||||
"parity-scale-codec",
|
||||
@@ -7756,7 +7756,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-rpc-server"
|
||||
version = "20.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"forwarded-header-value",
|
||||
@@ -7780,7 +7780,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-rpc-spec-v2"
|
||||
version = "0.48.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"futures",
|
||||
@@ -7812,7 +7812,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-service"
|
||||
version = "0.49.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"directories",
|
||||
@@ -7875,7 +7875,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-state-db"
|
||||
version = "0.37.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"log",
|
||||
"parity-scale-codec",
|
||||
@@ -7886,7 +7886,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-sysinfo"
|
||||
version = "41.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"derive_more",
|
||||
"futures",
|
||||
@@ -7907,7 +7907,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-telemetry"
|
||||
version = "28.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"futures",
|
||||
@@ -7927,7 +7927,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-tracing"
|
||||
version = "38.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"console",
|
||||
@@ -7954,7 +7954,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-tracing-proc-macro"
|
||||
version = "11.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"proc-macro-crate 3.2.0",
|
||||
"proc-macro2",
|
||||
@@ -7965,7 +7965,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-transaction-pool"
|
||||
version = "38.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -7996,7 +7996,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-transaction-pool-api"
|
||||
version = "38.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -8012,7 +8012,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sc-utils"
|
||||
version = "18.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"futures",
|
||||
@@ -8266,19 +8266,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"borsh",
|
||||
"frame-support",
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
"serai-coins-primitives",
|
||||
"serai-emissions-primitives",
|
||||
"serai-genesis-liquidity-primitives",
|
||||
"serai-in-instructions-primitives",
|
||||
"serai-primitives",
|
||||
"serai-signals-primitives",
|
||||
"serai-validator-sets-primitives",
|
||||
"serde",
|
||||
"sp-consensus-babe",
|
||||
"sp-consensus-grandpa",
|
||||
"sp-core",
|
||||
"sp-runtime",
|
||||
]
|
||||
@@ -8885,18 +8875,12 @@ dependencies = [
|
||||
name = "serai-primitives"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"bitvec",
|
||||
"borsh",
|
||||
"ciphersuite",
|
||||
"frame-support",
|
||||
"parity-scale-codec",
|
||||
"rand_core",
|
||||
"scale-info",
|
||||
"serde",
|
||||
"sp-application-crypto",
|
||||
"dkg",
|
||||
"sp-core",
|
||||
"sp-io",
|
||||
"sp-runtime",
|
||||
"sp-std",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -9599,7 +9583,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-api"
|
||||
version = "35.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"hash-db",
|
||||
"log",
|
||||
@@ -9620,7 +9604,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-api-proc-macro"
|
||||
version = "21.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"blake2",
|
||||
@@ -9634,7 +9618,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-application-crypto"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
@@ -9646,7 +9630,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-arithmetic"
|
||||
version = "26.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"integer-sqrt",
|
||||
"num-traits",
|
||||
@@ -9659,7 +9643,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-authority-discovery"
|
||||
version = "35.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
@@ -9671,7 +9655,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-block-builder"
|
||||
version = "35.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"sp-api",
|
||||
"sp-inherents",
|
||||
@@ -9681,7 +9665,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-blockchain"
|
||||
version = "38.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"parity-scale-codec",
|
||||
@@ -9700,7 +9684,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-consensus"
|
||||
version = "0.41.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"futures",
|
||||
@@ -9715,7 +9699,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-consensus-babe"
|
||||
version = "0.41.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"parity-scale-codec",
|
||||
@@ -9733,7 +9717,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-consensus-grandpa"
|
||||
version = "22.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"finality-grandpa",
|
||||
"log",
|
||||
@@ -9750,7 +9734,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-consensus-slots"
|
||||
version = "0.41.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
@@ -9761,7 +9745,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-core"
|
||||
version = "35.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"array-bytes",
|
||||
"bitflags 1.3.2",
|
||||
@@ -9802,7 +9786,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-crypto-hashing"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"byteorder",
|
||||
@@ -9813,7 +9797,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-crypto-hashing-proc-macro"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"sp-crypto-hashing",
|
||||
@@ -9823,7 +9807,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-database"
|
||||
version = "10.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"kvdb",
|
||||
"parking_lot 0.12.3",
|
||||
@@ -9832,7 +9816,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-debug-derive"
|
||||
version = "14.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -9842,7 +9826,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-externalities"
|
||||
version = "0.30.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"environmental",
|
||||
"parity-scale-codec",
|
||||
@@ -9852,7 +9836,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-genesis-builder"
|
||||
version = "0.16.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
@@ -9864,7 +9848,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-inherents"
|
||||
version = "35.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"impl-trait-for-tuples",
|
||||
@@ -9877,7 +9861,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-io"
|
||||
version = "39.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"log",
|
||||
@@ -9898,7 +9882,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-keyring"
|
||||
version = "40.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"sp-core",
|
||||
"sp-runtime",
|
||||
@@ -9908,7 +9892,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-keystore"
|
||||
version = "0.41.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"parking_lot 0.12.3",
|
||||
@@ -9919,7 +9903,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-maybe-compressed-blob"
|
||||
version = "11.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"thiserror 2.0.11",
|
||||
"zstd 0.13.2",
|
||||
@@ -9928,7 +9912,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-metadata-ir"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-metadata",
|
||||
"parity-scale-codec",
|
||||
@@ -9938,7 +9922,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-offchain"
|
||||
version = "35.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"sp-api",
|
||||
"sp-core",
|
||||
@@ -9948,7 +9932,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-panic-handler"
|
||||
version = "13.0.1"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"regex",
|
||||
@@ -9957,7 +9941,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-rpc"
|
||||
version = "33.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"rustc-hash 1.1.0",
|
||||
"serde",
|
||||
@@ -9967,7 +9951,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-runtime"
|
||||
version = "40.1.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"either",
|
||||
"hash256-std-hasher",
|
||||
@@ -9993,7 +9977,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-runtime-interface"
|
||||
version = "29.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"impl-trait-for-tuples",
|
||||
@@ -10011,7 +9995,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-runtime-interface-proc-macro"
|
||||
version = "18.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"expander",
|
||||
@@ -10024,7 +10008,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-session"
|
||||
version = "37.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"scale-info",
|
||||
@@ -10038,7 +10022,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-staking"
|
||||
version = "37.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"impl-trait-for-tuples",
|
||||
"parity-scale-codec",
|
||||
@@ -10051,7 +10035,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-state-machine"
|
||||
version = "0.44.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"hash-db",
|
||||
"log",
|
||||
@@ -10071,12 +10055,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-std"
|
||||
version = "14.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
|
||||
[[package]]
|
||||
name = "sp-storage"
|
||||
version = "22.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"impl-serde",
|
||||
"parity-scale-codec",
|
||||
@@ -10088,7 +10072,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-timestamp"
|
||||
version = "35.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"parity-scale-codec",
|
||||
@@ -10100,7 +10084,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-tracing"
|
||||
version = "17.0.1"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"tracing",
|
||||
@@ -10111,7 +10095,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-transaction-pool"
|
||||
version = "35.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"sp-api",
|
||||
"sp-runtime",
|
||||
@@ -10120,7 +10104,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-trie"
|
||||
version = "38.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"hash-db",
|
||||
@@ -10142,7 +10126,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-version"
|
||||
version = "38.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"impl-serde",
|
||||
"parity-scale-codec",
|
||||
@@ -10159,7 +10143,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-version-proc-macro"
|
||||
version = "15.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"parity-scale-codec",
|
||||
"proc-macro-warning",
|
||||
@@ -10171,7 +10155,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-wasm-interface"
|
||||
version = "21.0.1"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"impl-trait-for-tuples",
|
||||
@@ -10183,7 +10167,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sp-weights"
|
||||
version = "31.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"bounded-collections",
|
||||
"parity-scale-codec",
|
||||
@@ -10344,7 +10328,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "substrate-bip39"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"hmac",
|
||||
"pbkdf2",
|
||||
@@ -10369,12 +10353,12 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "substrate-build-script-utils"
|
||||
version = "11.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
|
||||
[[package]]
|
||||
name = "substrate-frame-rpc-system"
|
||||
version = "42.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"frame-system-rpc-runtime-api",
|
||||
"futures",
|
||||
@@ -10393,7 +10377,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "substrate-prometheus-endpoint"
|
||||
version = "0.17.1"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
@@ -10407,7 +10391,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "substrate-wasm-builder"
|
||||
version = "25.0.0"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#fe70c9f0508b97f72c5f5ecf4d488feb35fa5f25"
|
||||
source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#1aac7f6d602ea1c4f2059c4e80caacba3cbf3286"
|
||||
dependencies = [
|
||||
"build-helper",
|
||||
"cargo_metadata",
|
||||
|
||||
@@ -7,8 +7,6 @@ db-urls = ["https://github.com/rustsec/advisory-db"]
|
||||
yanked = "deny"
|
||||
|
||||
ignore = [
|
||||
"RUSTSEC-2020-0168", # mach is unmaintained
|
||||
"RUSTSEC-2021-0139", # https://github.com/serai-dex/serai/228
|
||||
"RUSTSEC-2022-0061", # https://github.com/serai-dex/serai/227
|
||||
"RUSTSEC-2024-0370", # proc-macro-error is unmaintained
|
||||
"RUSTSEC-2024-0384", # instant is unmaintained
|
||||
@@ -123,7 +121,7 @@ wildcards = "warn"
|
||||
highlight = "all"
|
||||
deny = [
|
||||
{ name = "serde_derive", version = ">=1.0.172, <1.0.185" },
|
||||
{ name = "hashbrown", version = ">=0.15" },
|
||||
{ name = "hashbrown", version = "=0.15.0" },
|
||||
]
|
||||
|
||||
[sources]
|
||||
|
||||
@@ -11,6 +11,7 @@ RUN rm -rf /etc/apt/sources.list.d/debian.sources && \
|
||||
RUN apt update && apt upgrade && apt install clang -y
|
||||
|
||||
# Add the wasm toolchain
|
||||
RUN rustup component add rust-src
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
|
||||
FROM deterministic
|
||||
|
||||
@@ -162,6 +162,7 @@ RUN apt install -y pkg-config clang
|
||||
RUN apt install -y make protobuf-compiler
|
||||
|
||||
# Add the wasm toolchain
|
||||
RUN rustup component add rust-src
|
||||
RUN rustup target add wasm32-unknown-unknown
|
||||
|
||||
{prelude}
|
||||
|
||||
@@ -12,76 +12,38 @@ rust-version = "1.80"
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["serde"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
bitvec = { version = "1", default-features = false, features = ["alloc", "serde"] }
|
||||
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "bit-vec"] }
|
||||
scale-info = { version = "2", default-features = false, features = ["derive", "bit-vec"] }
|
||||
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true }
|
||||
serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true }
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
|
||||
|
||||
bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
||||
sp-core = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
|
||||
sp-consensus-babe = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
sp-consensus-grandpa = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
|
||||
frame-support = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
serde = { version = "1", default-features = false, features = ["derive"], optional = true }
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"], optional = true }
|
||||
scale-info = { version = "2", default-features = false, features = ["derive"], optional = true }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false, features = ["serde"], optional = true }
|
||||
|
||||
serai-primitives = { path = "../primitives", version = "0.1", default-features = false }
|
||||
serai-coins-primitives = { path = "../coins/primitives", version = "0.1", default-features = false }
|
||||
serai-validator-sets-primitives = { path = "../validator-sets/primitives", version = "0.1", default-features = false }
|
||||
serai-genesis-liquidity-primitives = { path = "../genesis-liquidity/primitives", version = "0.1", default-features = false }
|
||||
serai-emissions-primitives = { path = "../emissions/primitives", version = "0.1", default-features = false }
|
||||
serai-in-instructions-primitives = { path = "../in-instructions/primitives", version = "0.1", default-features = false }
|
||||
serai-signals-primitives = { path = "../signals/primitives", version = "0.1", default-features = false }
|
||||
|
||||
[features]
|
||||
std = [
|
||||
"borsh/std",
|
||||
|
||||
"bitvec/std",
|
||||
|
||||
"scale/std",
|
||||
"scale-info/std",
|
||||
|
||||
"borsh?/std",
|
||||
"serde?/std",
|
||||
|
||||
"sp-core/std",
|
||||
"sp-runtime/std",
|
||||
|
||||
"sp-consensus-babe/std",
|
||||
"sp-consensus-grandpa/std",
|
||||
|
||||
"frame-support/std",
|
||||
"serde?/std",
|
||||
"scale?/std",
|
||||
"scale-info?/std",
|
||||
"sp-runtime?/std",
|
||||
|
||||
"serai-primitives/std",
|
||||
"serai-coins-primitives/std",
|
||||
"serai-validator-sets-primitives/std",
|
||||
"serai-genesis-liquidity-primitives/std",
|
||||
"serai-emissions-primitives/std",
|
||||
"serai-in-instructions-primitives/std",
|
||||
"serai-signals-primitives/std",
|
||||
]
|
||||
borsh = [
|
||||
"dep:borsh",
|
||||
"serai-primitives/borsh",
|
||||
"serai-coins-primitives/borsh",
|
||||
"serai-validator-sets-primitives/borsh",
|
||||
"serai-genesis-liquidity-primitives/borsh",
|
||||
"serai-in-instructions-primitives/borsh",
|
||||
"serai-signals-primitives/borsh",
|
||||
]
|
||||
serde = [
|
||||
"dep:serde",
|
||||
"serai-primitives/serde",
|
||||
"serai-coins-primitives/serde",
|
||||
"serai-validator-sets-primitives/serde",
|
||||
"serai-genesis-liquidity-primitives/serde",
|
||||
"serai-in-instructions-primitives/serde",
|
||||
"serai-signals-primitives/serde",
|
||||
]
|
||||
substrate = ["serde", "scale", "scale-info", "sp-runtime"]
|
||||
default = ["std"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Luke Parker
|
||||
Copyright (c) 2023-2025 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
|
||||
|
||||
4
substrate/abi/README.md
Normal file
4
substrate/abi/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# serai-abi
|
||||
|
||||
Serai's ABI, inclusive to the transaction, event, and block types. MIT-licensed to ensure usability
|
||||
in a variety of contexts.
|
||||
@@ -1,17 +0,0 @@
|
||||
use sp_consensus_babe::EquivocationProof;
|
||||
|
||||
use serai_primitives::{Header, SeraiAddress};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub struct ReportEquivocation {
|
||||
pub equivocation_proof: alloc::boxed::Box<EquivocationProof<Header>>,
|
||||
pub key_owner_proof: SeraiAddress,
|
||||
}
|
||||
|
||||
// We could define a Babe Config here and use the literal pallet_babe::Call
|
||||
// The disadvantage to this would be the complexity and presence of junk fields such as `__Ignore`
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub enum Call {
|
||||
report_equivocation(ReportEquivocation),
|
||||
report_equivocation_unsigned(ReportEquivocation),
|
||||
}
|
||||
250
substrate/abi/src/block.rs
Normal file
250
substrate/abi/src/block.rs
Normal file
@@ -0,0 +1,250 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use crate::{primitives::BlockHash, Transaction};
|
||||
|
||||
/// A V1 header for a block.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct HeaderV1 {
|
||||
/// The index of this block on the blockchain.
|
||||
///
|
||||
/// The genesis block has number 0.
|
||||
pub number: u64,
|
||||
/// The block this header builds upon.
|
||||
pub parent_hash: BlockHash,
|
||||
/// The root of a Merkle tree commiting to the transactions within this block.
|
||||
// TODO: Review the format of this defined by Substrate
|
||||
pub transactions_root: [u8; 32],
|
||||
/// A commitment to the consensus data used to justify adding this block to the blockchain.
|
||||
pub consensus_commitment: [u8; 32],
|
||||
}
|
||||
|
||||
/// A header for a block.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Header {
|
||||
/// A version 1 header.
|
||||
V1(HeaderV1),
|
||||
}
|
||||
|
||||
impl Header {
|
||||
/// Get the hash of the header.
|
||||
pub fn number(&self) -> u64 {
|
||||
match self {
|
||||
Header::V1(HeaderV1 { number, .. }) => *number,
|
||||
}
|
||||
}
|
||||
/// Get the hash of the header.
|
||||
pub fn parent_hash(&self) -> BlockHash {
|
||||
match self {
|
||||
Header::V1(HeaderV1 { parent_hash, .. }) => *parent_hash,
|
||||
}
|
||||
}
|
||||
/// Get the hash of the header.
|
||||
pub fn transactions_root(&self) -> [u8; 32] {
|
||||
match self {
|
||||
Header::V1(HeaderV1 { transactions_root, .. }) => *transactions_root,
|
||||
}
|
||||
}
|
||||
/// Get the hash of the header.
|
||||
pub fn hash(&self) -> BlockHash {
|
||||
BlockHash(sp_core::blake2_256(&borsh::to_vec(self).unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
/// A block.
|
||||
///
|
||||
/// This does not guarantee consistency. The header's `transactions_root` may not match the
|
||||
/// contained transactions.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Block {
|
||||
/// The block's header.
|
||||
pub header: Header,
|
||||
/// The block's transactions.
|
||||
pub transactions: Vec<Transaction>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "substrate")]
|
||||
mod substrate {
|
||||
use scale::{Encode, Decode};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use sp_core::H256;
|
||||
use sp_runtime::{
|
||||
generic::Digest,
|
||||
traits::{Header as HeaderTrait, HeaderProvider, Block as BlockTrait},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
/// The consensus data for a V1 header.
|
||||
///
|
||||
/// This is not considered part of the protocol proper and may be pruned in the future. It's
|
||||
/// solely considered used for consensus now.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, sp_runtime::Serialize)]
|
||||
pub struct ConsensusV1 {
|
||||
/// The state root.
|
||||
state_root: H256,
|
||||
/// The consensus digests.
|
||||
digest: Digest,
|
||||
}
|
||||
|
||||
/// A V1 header for a block, as needed by Substrate.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, sp_runtime::Serialize)]
|
||||
pub struct SubstrateHeaderV1 {
|
||||
number: u64,
|
||||
parent_hash: H256,
|
||||
transactions_root: H256,
|
||||
consensus: ConsensusV1,
|
||||
}
|
||||
|
||||
/// A header for a block, as needed by Substrate.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, sp_runtime::Serialize)]
|
||||
pub enum SubstrateHeader {
|
||||
/// A version 1 header.
|
||||
V1(SubstrateHeaderV1),
|
||||
}
|
||||
|
||||
impl From<&SubstrateHeader> for Header {
|
||||
fn from(header: &SubstrateHeader) -> Header {
|
||||
match header {
|
||||
SubstrateHeader::V1(header) => Header::V1(HeaderV1 {
|
||||
number: header.number,
|
||||
parent_hash: BlockHash(header.parent_hash.0),
|
||||
transactions_root: header.transactions_root.0,
|
||||
consensus_commitment: sp_core::blake2_256(&header.consensus.encode()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A block, as needed by Substrate.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, sp_runtime::Serialize)]
|
||||
pub struct SubstrateBlock {
|
||||
header: SubstrateHeader,
|
||||
#[serde(skip)] // This makes this unsafe to deserialize, but we don't impl `Deserialize`
|
||||
transactions: Vec<Transaction>,
|
||||
}
|
||||
|
||||
impl HeaderTrait for SubstrateHeader {
|
||||
type Number = u64;
|
||||
type Hash = H256;
|
||||
type Hashing = sp_runtime::traits::BlakeTwo256;
|
||||
|
||||
fn new(
|
||||
number: Self::Number,
|
||||
extrinsics_root: Self::Hash,
|
||||
state_root: Self::Hash,
|
||||
parent_hash: Self::Hash,
|
||||
digest: Digest,
|
||||
) -> Self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 {
|
||||
number,
|
||||
parent_hash,
|
||||
transactions_root: extrinsics_root,
|
||||
consensus: ConsensusV1 { state_root, digest },
|
||||
})
|
||||
}
|
||||
|
||||
fn number(&self) -> &Self::Number {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { number, .. }) => number,
|
||||
}
|
||||
}
|
||||
fn set_number(&mut self, number: Self::Number) {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { number: existing, .. }) => {
|
||||
*existing = number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extrinsics_root(&self) -> &Self::Hash {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { transactions_root, .. }) => transactions_root,
|
||||
}
|
||||
}
|
||||
fn set_extrinsics_root(&mut self, extrinsics_root: Self::Hash) {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { transactions_root, .. }) => {
|
||||
*transactions_root = extrinsics_root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn state_root(&self) -> &Self::Hash {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { consensus, .. }) => &consensus.state_root,
|
||||
}
|
||||
}
|
||||
fn set_state_root(&mut self, state_root: Self::Hash) {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { consensus, .. }) => {
|
||||
consensus.state_root = state_root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_hash(&self) -> &Self::Hash {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { parent_hash, .. }) => parent_hash,
|
||||
}
|
||||
}
|
||||
fn set_parent_hash(&mut self, parent_hash: Self::Hash) {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { parent_hash: existing, .. }) => {
|
||||
*existing = parent_hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn digest(&self) -> &Digest {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { consensus, .. }) => &consensus.digest,
|
||||
}
|
||||
}
|
||||
fn digest_mut(&mut self) -> &mut Digest {
|
||||
match self {
|
||||
SubstrateHeader::V1(SubstrateHeaderV1 { consensus, .. }) => &mut consensus.digest,
|
||||
}
|
||||
}
|
||||
|
||||
fn hash(&self) -> H256 {
|
||||
H256::from(Header::from(self).hash().0)
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderProvider for SubstrateBlock {
|
||||
type HeaderT = SubstrateHeader;
|
||||
}
|
||||
|
||||
impl BlockTrait for SubstrateBlock {
|
||||
type Extrinsic = Transaction;
|
||||
type Header = SubstrateHeader;
|
||||
type Hash = H256;
|
||||
fn header(&self) -> &Self::Header {
|
||||
&self.header
|
||||
}
|
||||
fn extrinsics(&self) -> &[Self::Extrinsic] {
|
||||
&self.transactions
|
||||
}
|
||||
fn deconstruct(self) -> (Self::Header, Vec<Self::Extrinsic>) {
|
||||
(self.header, self.transactions)
|
||||
}
|
||||
fn new(header: Self::Header, transactions: Vec<Self::Extrinsic>) -> Self {
|
||||
Self { header, transactions }
|
||||
}
|
||||
fn encode_from(header: &Self::Header, transactions: &[Self::Extrinsic]) -> Vec<u8> {
|
||||
let header = header.encode();
|
||||
let transactions = transactions.encode();
|
||||
let mut block = header;
|
||||
block.extend(transactions);
|
||||
block
|
||||
}
|
||||
fn hash(&self) -> Self::Hash {
|
||||
self.header.hash()
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "substrate")]
|
||||
pub use substrate::*;
|
||||
@@ -1,25 +1,70 @@
|
||||
use serai_primitives::{Balance, SeraiAddress};
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
pub use serai_coins_primitives as primitives;
|
||||
use primitives::OutInstructionWithBalance;
|
||||
use serai_primitives::{
|
||||
address::SeraiAddress, balance::Balance, instructions::OutInstructionWithBalance,
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
/// A call to coins.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Call {
|
||||
transfer { to: SeraiAddress, balance: Balance },
|
||||
burn { balance: Balance },
|
||||
burn_with_instruction { instruction: OutInstructionWithBalance },
|
||||
/// Transfer these coins to the specified address.
|
||||
transfer {
|
||||
/// The address to transfer to.
|
||||
to: SeraiAddress,
|
||||
/// The coins to transfer.
|
||||
coins: Balance,
|
||||
},
|
||||
/// Burn these coins.
|
||||
burn {
|
||||
/// The coins to burn.
|
||||
coins: Balance,
|
||||
},
|
||||
/// Burn these coins with an `OutInstruction` specified.
|
||||
burn_with_instruction {
|
||||
/// The `OutInstruction`, with the coins to burn.
|
||||
instruction: OutInstructionWithBalance,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Event {
|
||||
Mint { to: SeraiAddress, balance: Balance },
|
||||
Burn { from: SeraiAddress, balance: Balance },
|
||||
BurnWithInstruction { from: SeraiAddress, instruction: OutInstructionWithBalance },
|
||||
Transfer { from: SeraiAddress, to: SeraiAddress, balance: Balance },
|
||||
impl Call {
|
||||
pub(crate) fn is_signed(&self) -> bool {
|
||||
match self {
|
||||
Call::transfer { .. } | Call::burn { .. } | Call::burn_with_instruction { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event from the system.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Event {
|
||||
/// The specified coins were minted.
|
||||
Mint {
|
||||
/// The address minted to.
|
||||
to: SeraiAddress,
|
||||
/// The coins minted.
|
||||
coins: Balance,
|
||||
},
|
||||
/// The specified coins were burnt.
|
||||
Burn {
|
||||
/// The address burnt from.
|
||||
from: SeraiAddress,
|
||||
/// The coins burnt.
|
||||
coins: Balance,
|
||||
},
|
||||
/// The specified coins were burnt with an `OutInstruction` specified.
|
||||
BurnWithInstruction {
|
||||
/// The address burnt from.
|
||||
from: SeraiAddress,
|
||||
/// The `OutInstruction` specified, and the coins burnt.
|
||||
instruction: OutInstructionWithBalance,
|
||||
},
|
||||
/// The specified coins were transferred.
|
||||
Transfer {
|
||||
/// The address transferred from.
|
||||
from: SeraiAddress,
|
||||
/// The address transferred to.
|
||||
to: SeraiAddress,
|
||||
/// The coins transferred.
|
||||
coins: Balance,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,75 +1,121 @@
|
||||
use sp_runtime::BoundedVec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use serai_primitives::*;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
type PoolId = ExternalCoin;
|
||||
type MaxSwapPathLength = sp_core::ConstU32<3>;
|
||||
use serai_primitives::{
|
||||
address::SeraiAddress,
|
||||
coin::ExternalCoin,
|
||||
balance::{Amount, ExternalBalance, Balance},
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
/// A call to the DEX.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Call {
|
||||
/// Add liquidity.
|
||||
add_liquidity {
|
||||
/// The coin to add liquidity for.
|
||||
coin: ExternalCoin,
|
||||
coin_desired: SubstrateAmount,
|
||||
sri_desired: SubstrateAmount,
|
||||
coin_min: SubstrateAmount,
|
||||
sri_min: SubstrateAmount,
|
||||
mint_to: SeraiAddress,
|
||||
/// The intended amount of SRI to add as liquidity.
|
||||
sri_intended: Amount,
|
||||
/// The intended amount of the coin to add as liquidity.
|
||||
coin_intended: Amount,
|
||||
/// The minimum amount of SRI to add as liquidity.
|
||||
sri_minimum: Amount,
|
||||
/// The minimum amount of the coin to add as liquidity.
|
||||
coin_minimum: Amount,
|
||||
},
|
||||
/// Transfer these liquidity tokens to the specified address.
|
||||
transfer_liquidity {
|
||||
/// The address to transfer to.
|
||||
to: SeraiAddress,
|
||||
/// The liquidity tokens to transfer.
|
||||
liquidity_tokens: ExternalBalance,
|
||||
},
|
||||
/// Remove liquidity.
|
||||
remove_liquidity {
|
||||
coin: ExternalCoin,
|
||||
lp_token_burn: SubstrateAmount,
|
||||
coin_min_receive: SubstrateAmount,
|
||||
sri_min_receive: SubstrateAmount,
|
||||
withdraw_to: SeraiAddress,
|
||||
/// The liquidity tokens to burn, removing the underlying liquidity from the pool.
|
||||
///
|
||||
/// The `coin` within the balance is the coin to remove liquidity for.
|
||||
liquidity_tokens: ExternalBalance,
|
||||
/// The minimum amount of SRI to receive.
|
||||
sri_minimum: Amount,
|
||||
/// The minimum amount of the coin to receive.
|
||||
coin_minimum: Amount,
|
||||
},
|
||||
swap_exact_tokens_for_tokens {
|
||||
path: BoundedVec<Coin, MaxSwapPathLength>,
|
||||
amount_in: SubstrateAmount,
|
||||
amount_out_min: SubstrateAmount,
|
||||
send_to: SeraiAddress,
|
||||
/// Swap an exact amount of coins.
|
||||
swap_exact {
|
||||
/// The coins to swap.
|
||||
coins_to_swap: Balance,
|
||||
/// The minimum balance to receive.
|
||||
minimum_to_receive: Balance,
|
||||
},
|
||||
swap_tokens_for_exact_tokens {
|
||||
path: BoundedVec<Coin, MaxSwapPathLength>,
|
||||
amount_out: SubstrateAmount,
|
||||
amount_in_max: SubstrateAmount,
|
||||
send_to: SeraiAddress,
|
||||
/// Swap for an exact amount of coins.
|
||||
swap_for_exact {
|
||||
/// The coins to receive.
|
||||
coins_to_receive: Balance,
|
||||
/// The maximum amount to swap.
|
||||
maximum_to_swap: Balance,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
impl Call {
|
||||
pub(crate) fn is_signed(&self) -> bool {
|
||||
match self {
|
||||
Call::add_liquidity { .. } |
|
||||
Call::transfer_liquidity { .. } |
|
||||
Call::remove_liquidity { .. } |
|
||||
Call::swap_exact { .. } |
|
||||
Call::swap_for_exact { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event from the DEX.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Event {
|
||||
PoolCreated {
|
||||
pool_id: PoolId,
|
||||
pool_account: SeraiAddress,
|
||||
},
|
||||
|
||||
/// Liquidity was added to a pool.
|
||||
LiquidityAdded {
|
||||
who: SeraiAddress,
|
||||
mint_to: SeraiAddress,
|
||||
pool_id: PoolId,
|
||||
coin_amount: SubstrateAmount,
|
||||
sri_amount: SubstrateAmount,
|
||||
lp_token_minted: SubstrateAmount,
|
||||
/// The account which added the liquidity.
|
||||
origin: SeraiAddress,
|
||||
/// The account which received the liquidity tokens.
|
||||
recipient: SeraiAddress,
|
||||
/// The pool liquidity was added to.
|
||||
pool: ExternalCoin,
|
||||
/// The amount of liquidity tokens which were minted.
|
||||
liquidity_tokens_minted: Amount,
|
||||
/// The amount of the coin which was added to the pool's liquidity.
|
||||
coin_amount: Amount,
|
||||
/// The amount of SRI which was added to the pool's liquidity.
|
||||
sri_amount: Amount,
|
||||
},
|
||||
|
||||
/// Liquidity was removed from a pool.
|
||||
LiquidityRemoved {
|
||||
who: SeraiAddress,
|
||||
withdraw_to: SeraiAddress,
|
||||
pool_id: PoolId,
|
||||
coin_amount: SubstrateAmount,
|
||||
sri_amount: SubstrateAmount,
|
||||
lp_token_burned: SubstrateAmount,
|
||||
/// The account which removed the liquidity.
|
||||
origin: SeraiAddress,
|
||||
/// The pool liquidity was removed from.
|
||||
pool: ExternalCoin,
|
||||
/// The mount of liquidity tokens which were burnt.
|
||||
liquidity_tokens_burnt: Amount,
|
||||
/// The amount of the coin which was removed from the pool's liquidity.
|
||||
coin_amount: Amount,
|
||||
/// The amount of SRI which was removed from the pool's liquidity.
|
||||
sri_amount: Amount,
|
||||
},
|
||||
|
||||
SwapExecuted {
|
||||
who: SeraiAddress,
|
||||
send_to: SeraiAddress,
|
||||
path: BoundedVec<Coin, MaxSwapPathLength>,
|
||||
amount_in: SubstrateAmount,
|
||||
amount_out: SubstrateAmount,
|
||||
/// A swap through the liquidity pools occurred.
|
||||
Swap {
|
||||
/// The account which made the swap.
|
||||
origin: SeraiAddress,
|
||||
/// The recipient for the output of the swap.
|
||||
recipient: SeraiAddress,
|
||||
/// The deltas incurred by the pools.
|
||||
///
|
||||
/// For a swap of sriABC to sriDEF, this would be
|
||||
/// `[Balance { sriABC, 1 }, Balance { SRI, 2 }, Balance { sriDEF, 3 }]`, where
|
||||
/// `Balance { sriABC, 1 }` was added to the `sriABC-SRI` pool, `Balance { SRI, 2 }` was
|
||||
/// removed from the `sriABC-SRI` pool and added to the `sriDEF-SRI` pool, and
|
||||
/// `Balance { sriDEF, 3 }` was removed from the `sriDEF-SRI` pool.
|
||||
deltas: Vec<Balance>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
use serai_primitives::ExternalNetworkId;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
use serai_primitives::network_id::ExternalNetworkId;
|
||||
|
||||
/// An event from economic security.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Event {
|
||||
EconomicSecurityReached { network: ExternalNetworkId },
|
||||
/// Economic security was achieved for a network's validator set.
|
||||
EconomicSecurityAchieved {
|
||||
/// The network whose validator set achieved economic security.
|
||||
network: ExternalNetworkId,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pub use serai_emissions_primitives as primitives;
|
||||
@@ -1,20 +1,50 @@
|
||||
pub use serai_genesis_liquidity_primitives as primitives;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use serai_primitives::*;
|
||||
use primitives::*;
|
||||
use serai_primitives::{
|
||||
crypto::Signature, address::SeraiAddress, balance::ExternalBalance, genesis::GenesisValues,
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
/// A call to the genesis liquidity.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Call {
|
||||
remove_coin_liquidity { balance: ExternalBalance },
|
||||
oraclize_values { values: Values, signature: Signature },
|
||||
/// Oraclize the value of non-Bitcoin external coins relative to Bitcoin.
|
||||
oraclize_values {
|
||||
/// The values of the non-Bitcoin external coins.
|
||||
values: GenesisValues,
|
||||
/// The signature by the genesis validators for these values.
|
||||
signature: Signature,
|
||||
},
|
||||
/// Remove liquidity.
|
||||
remove_liquidity {
|
||||
/// The genesis liquidity to remove.
|
||||
balance: ExternalBalance,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
GenesisLiquidityAdded { by: SeraiAddress, balance: ExternalBalance },
|
||||
GenesisLiquidityRemoved { by: SeraiAddress, balance: ExternalBalance },
|
||||
GenesisLiquidityAddedToPool { coin: ExternalBalance, sri: Amount },
|
||||
impl Call {
|
||||
pub(crate) fn is_signed(&self) -> bool {
|
||||
match self {
|
||||
Call::oraclize_values { .. } => false,
|
||||
Call::remove_liquidity { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event from the genesis liquidity.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Event {
|
||||
/// Genesis liquidity added.
|
||||
GenesisLiquidityAdded {
|
||||
/// The recipient of the genesis liquidity.
|
||||
recipient: SeraiAddress,
|
||||
/// The coins added as genesis liquidity.
|
||||
balance: ExternalBalance,
|
||||
},
|
||||
/// Genesis liquidity removed.
|
||||
GenesisLiquidityRemoved {
|
||||
/// The account which removed the genesis liquidity.
|
||||
origin: SeraiAddress,
|
||||
/// The amount of genesis liquidity removed.
|
||||
balance: ExternalBalance,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
use sp_consensus_grandpa::EquivocationProof;
|
||||
|
||||
use serai_primitives::{BlockNumber, SeraiAddress};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub struct ReportEquivocation {
|
||||
pub equivocation_proof: alloc::boxed::Box<EquivocationProof<[u8; 32], BlockNumber>>,
|
||||
pub key_owner_proof: SeraiAddress,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub enum Call {
|
||||
report_equivocation(ReportEquivocation),
|
||||
report_equivocation_unsigned(ReportEquivocation),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Event {
|
||||
NewAuthorities { authority_set: alloc::vec::Vec<(SeraiAddress, u64)> },
|
||||
// TODO: Remove these
|
||||
Paused,
|
||||
Resumed,
|
||||
}
|
||||
@@ -1,30 +1,47 @@
|
||||
use serai_primitives::*;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
pub use serai_in_instructions_primitives as primitives;
|
||||
use primitives::SignedBatch;
|
||||
use serai_validator_sets_primitives::Session;
|
||||
use serai_primitives::{
|
||||
BlockHash, network_id::ExternalNetworkId, validator_sets::Session, instructions::SignedBatch,
|
||||
};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
/// A call to `InInstruction`s.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Call {
|
||||
execute_batch { batch: SignedBatch },
|
||||
/// Execute a batch of `InInstruction`s.
|
||||
execute_batch {
|
||||
/// The batch to execute.
|
||||
batch: SignedBatch,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
impl Call {
|
||||
pub(crate) fn is_signed(&self) -> bool {
|
||||
match self {
|
||||
Call::execute_batch { .. } => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event from `InInstruction`s.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Event {
|
||||
/// A batch of `InInstruction`s was executed.
|
||||
Batch {
|
||||
/// The network for which a batch was executed.
|
||||
network: ExternalNetworkId,
|
||||
/// The session which published the batch.
|
||||
publishing_session: Session,
|
||||
/// The ID of the batch.
|
||||
id: u32,
|
||||
/// The hash of the block on the external network which caused this batch's creation.
|
||||
external_network_block_hash: BlockHash,
|
||||
/// The hash of the `InInstruction`s within this batch.
|
||||
in_instructions_hash: [u8; 32],
|
||||
/// The results of each `InInstruction` within the batch.
|
||||
#[borsh(
|
||||
serialize_with = "serai_primitives::sp_borsh::borsh_serialize_bitvec",
|
||||
deserialize_with = "serai_primitives::sp_borsh::borsh_deserialize_bitvec"
|
||||
)]
|
||||
in_instruction_results: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
|
||||
},
|
||||
Halt {
|
||||
network: ExternalNetworkId,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,94 +1,98 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
pub use serai_primitives as primitives;
|
||||
|
||||
/// Call/Event for the system.
|
||||
pub mod system;
|
||||
|
||||
pub mod timestamp;
|
||||
|
||||
/// Call/Event for coins.
|
||||
pub mod coins;
|
||||
pub mod liquidity_tokens;
|
||||
pub mod dex;
|
||||
|
||||
/// Call/Event for validator sets.
|
||||
pub mod validator_sets;
|
||||
|
||||
pub mod genesis_liquidity;
|
||||
pub mod emissions;
|
||||
|
||||
pub mod economic_security;
|
||||
|
||||
pub mod in_instructions;
|
||||
|
||||
/// Call/Event for signals.
|
||||
pub mod signals;
|
||||
|
||||
pub mod babe;
|
||||
pub mod grandpa;
|
||||
/// Call/Event for the DEX.
|
||||
pub mod dex;
|
||||
|
||||
pub mod tx;
|
||||
/// Call/Event for genesis liquidity.
|
||||
pub mod genesis_liquidity;
|
||||
/// Event for economic security.
|
||||
pub mod economic_security;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
/// Call/Event for `InInstruction`s.
|
||||
pub mod in_instructions;
|
||||
|
||||
mod transaction;
|
||||
pub use transaction::*;
|
||||
|
||||
mod block;
|
||||
pub use block::*;
|
||||
|
||||
/// All calls.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
#[borsh(use_discriminant = true)]
|
||||
#[repr(u8)]
|
||||
pub enum Call {
|
||||
Timestamp(timestamp::Call),
|
||||
Coins(coins::Call),
|
||||
LiquidityTokens(liquidity_tokens::Call),
|
||||
Dex(dex::Call),
|
||||
ValidatorSets(validator_sets::Call),
|
||||
GenesisLiquidity(genesis_liquidity::Call),
|
||||
InInstructions(in_instructions::Call),
|
||||
Signals(signals::Call),
|
||||
Babe(babe::Call),
|
||||
Grandpa(grandpa::Call),
|
||||
// The call for the system.
|
||||
// System(system::Call) = 0,
|
||||
/// The call for coins.
|
||||
Coins(coins::Call) = 1,
|
||||
/// The call for validator sets.
|
||||
ValidatorSets(validator_sets::Call) = 2,
|
||||
/// The call for signals.
|
||||
Signals(signals::Call) = 3,
|
||||
/// The call for the DEX.
|
||||
Dex(dex::Call) = 4,
|
||||
/// The call for genesis liquidity.
|
||||
GenesisLiquidity(genesis_liquidity::Call) = 5,
|
||||
// The call for economic security.
|
||||
// EconomicSecurity = 6,
|
||||
/// The call for `InInstruction`s.
|
||||
InInstructions(in_instructions::Call) = 7,
|
||||
}
|
||||
|
||||
// TODO: Remove this
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
pub enum TransactionPaymentEvent {
|
||||
TransactionFeePaid { who: serai_primitives::SeraiAddress, actual_fee: u64, tip: u64 },
|
||||
impl Call {
|
||||
pub(crate) fn is_signed(&self) -> bool {
|
||||
match self {
|
||||
Call::Coins(call) => call.is_signed(),
|
||||
Call::ValidatorSets(call) => call.is_signed(),
|
||||
Call::Signals(call) => call.is_signed(),
|
||||
Call::Dex(call) => call.is_signed(),
|
||||
Call::GenesisLiquidity(call) => call.is_signed(),
|
||||
Call::InInstructions(call) => call.is_signed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
/// All events.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
#[borsh(use_discriminant = true)]
|
||||
#[repr(u8)]
|
||||
pub enum Event {
|
||||
System(system::Event),
|
||||
Timestamp,
|
||||
TransactionPayment(TransactionPaymentEvent),
|
||||
Coins(coins::Event),
|
||||
LiquidityTokens(liquidity_tokens::Event),
|
||||
Dex(dex::Event),
|
||||
ValidatorSets(validator_sets::Event),
|
||||
GenesisLiquidity(genesis_liquidity::Event),
|
||||
Emissions,
|
||||
EconomicSecurity(economic_security::Event),
|
||||
InInstructions(in_instructions::Event),
|
||||
Signals(signals::Event),
|
||||
Babe,
|
||||
Grandpa(grandpa::Event),
|
||||
/// The event for the system.
|
||||
System(system::Event) = 0,
|
||||
/// The event for coins.
|
||||
Coins(coins::Event) = 1,
|
||||
/// The event for validator sets.
|
||||
ValidatorSets(validator_sets::Event) = 2,
|
||||
/// The event for signals.
|
||||
Signals(signals::Event) = 3,
|
||||
/// The event for the DEX.
|
||||
Dex(dex::Event) = 4,
|
||||
/// The event for genesis liquidity.
|
||||
GenesisLiquidity(genesis_liquidity::Event) = 5,
|
||||
/// The event for economic security.
|
||||
EconomicSecurity(economic_security::Event) = 6,
|
||||
/// The event for `InInstruction`s.
|
||||
InInstructions(in_instructions::Event) = 7,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub struct Extra {
|
||||
pub era: sp_runtime::generic::Era,
|
||||
#[codec(compact)]
|
||||
pub nonce: u32,
|
||||
#[codec(compact)]
|
||||
pub tip: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub struct SignedPayloadExtra {
|
||||
pub spec_version: u32,
|
||||
pub tx_version: u32,
|
||||
pub genesis: [u8; 32],
|
||||
pub mortality_checkpoint: [u8; 32],
|
||||
}
|
||||
|
||||
pub type Transaction = tx::Transaction<Call, Extra>;
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
use serai_primitives::{Balance, SeraiAddress};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Call {
|
||||
burn { balance: Balance },
|
||||
transfer { to: SeraiAddress, balance: Balance },
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Event {
|
||||
Mint { to: SeraiAddress, balance: Balance },
|
||||
Burn { from: SeraiAddress, balance: Balance },
|
||||
Transfer { from: SeraiAddress, to: SeraiAddress, balance: Balance },
|
||||
}
|
||||
@@ -1,59 +1,132 @@
|
||||
use serai_primitives::{NetworkId, SeraiAddress};
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use serai_validator_sets_primitives::ValidatorSet;
|
||||
use serai_primitives::{
|
||||
address::SeraiAddress, network_id::NetworkId, validator_sets::ValidatorSet, signals::Signal,
|
||||
};
|
||||
|
||||
pub use serai_signals_primitives as primitives;
|
||||
use primitives::SignalId;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
/// A call to signals.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Call {
|
||||
register_retirement_signal { in_favor_of: [u8; 32] },
|
||||
revoke_retirement_signal { retirement_signal_id: [u8; 32] },
|
||||
favor { signal_id: SignalId, for_network: NetworkId },
|
||||
revoke_favor { signal_id: SignalId, for_network: NetworkId },
|
||||
stand_against { signal_id: SignalId, for_network: NetworkId },
|
||||
/// Register a retirement signal.
|
||||
register_retirement_signal {
|
||||
/// The protocol favored over the current protocol.
|
||||
in_favor_of: [u8; 32],
|
||||
},
|
||||
/// Revoke a retirement signal.
|
||||
revoke_retirement_signal {
|
||||
/// The protocol which was favored over the current protocol
|
||||
was_in_favor_of: [u8; 32],
|
||||
},
|
||||
/// Favor a signal.
|
||||
favor {
|
||||
/// The signal to favor.
|
||||
signal: Signal,
|
||||
/// The network this validator is expressing favor with.
|
||||
///
|
||||
/// A validator may be an active validator for multiple networks. The validator must specify
|
||||
/// which network they're expressing favor with in this call.
|
||||
with_network: NetworkId,
|
||||
},
|
||||
/// Revoke favor for a signal.
|
||||
revoke_favor {
|
||||
/// The signal to revoke favor for.
|
||||
signal: Signal,
|
||||
/// The network this validator is revoking favor with.
|
||||
///
|
||||
/// A validator may have expressed favor with multiple networks. The validator must specify
|
||||
/// which network they're revoking favor with in this call.
|
||||
with_network: NetworkId,
|
||||
},
|
||||
/// Stand against a signal.
|
||||
///
|
||||
/// This has no effects other than emitting an event that this signal is stood against. If the
|
||||
/// origin has prior expressed favor, they must still call `revoke_favor` for each network they
|
||||
/// expressed favor with.
|
||||
stand_against {
|
||||
/// The signal to stand against.
|
||||
signal: Signal,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
impl Call {
|
||||
pub(crate) fn is_signed(&self) -> bool {
|
||||
match self {
|
||||
Call::register_retirement_signal { .. } |
|
||||
Call::revoke_retirement_signal { .. } |
|
||||
Call::favor { .. } |
|
||||
Call::revoke_favor { .. } |
|
||||
Call::stand_against { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event from signals.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Event {
|
||||
/// A retirement signal has been registered.
|
||||
RetirementSignalRegistered {
|
||||
signal_id: [u8; 32],
|
||||
/// The retirement signal's ID.
|
||||
signal: [u8; 32],
|
||||
/// The protocol retirement is proposed in favor of.
|
||||
in_favor_of: [u8; 32],
|
||||
/// The address which registered this signal.
|
||||
registrant: SeraiAddress,
|
||||
},
|
||||
/// A retirement signal was revoked.
|
||||
RetirementSignalRevoked {
|
||||
signal_id: [u8; 32],
|
||||
/// The retirement signal's ID.
|
||||
signal: [u8; 32],
|
||||
},
|
||||
/// A signal was favored.
|
||||
SignalFavored {
|
||||
signal_id: SignalId,
|
||||
/// The signal favored.
|
||||
signal: Signal,
|
||||
/// The validator the signal was favored by.
|
||||
by: SeraiAddress,
|
||||
for_network: NetworkId,
|
||||
},
|
||||
SetInFavor {
|
||||
signal_id: SignalId,
|
||||
set: ValidatorSet,
|
||||
},
|
||||
RetirementSignalLockedIn {
|
||||
signal_id: [u8; 32],
|
||||
},
|
||||
SetNoLongerInFavor {
|
||||
signal_id: SignalId,
|
||||
set: ValidatorSet,
|
||||
/// The network with which the signal was favored.
|
||||
with_network: NetworkId,
|
||||
},
|
||||
/// Favor for a signal was revoked.
|
||||
FavorRevoked {
|
||||
signal_id: SignalId,
|
||||
/// The signal whose favor was revoked.
|
||||
signal: Signal,
|
||||
/// The validator who revoked their favor for the signal.
|
||||
by: SeraiAddress,
|
||||
for_network: NetworkId,
|
||||
/// The network with which favor for the signal was revoked.
|
||||
with_network: NetworkId,
|
||||
},
|
||||
/// A supermajority of a validator set now favor a signal.
|
||||
SetInFavor {
|
||||
/// The signal which now has a supermajority of a validator set favoring it.
|
||||
signal: Signal,
|
||||
/// The validator set which is now considered to favor the signal.
|
||||
set: ValidatorSet,
|
||||
},
|
||||
/// A validator set is no longer considered to favor a signal.
|
||||
SetNoLongerInFavor {
|
||||
/// The signal which no longer has the validator set considered in favor of it.
|
||||
signal: Signal,
|
||||
/// The validator set which is no longer considered to be in favor of the signal.
|
||||
set: ValidatorSet,
|
||||
},
|
||||
/// A retirement signal has been locked in.
|
||||
RetirementSignalLockedIn {
|
||||
/// The signal which has been locked in.
|
||||
signal: [u8; 32],
|
||||
},
|
||||
/// A validator set's ability to publish batches was halted.
|
||||
///
|
||||
/// This also halts set rotation in effect, as handovers are via new sets starting to publish
|
||||
/// batches.
|
||||
SetHalted {
|
||||
/// The signal which has been locked in.
|
||||
signal: [u8; 32],
|
||||
},
|
||||
/// An account has stood against a signal.
|
||||
AgainstSignal {
|
||||
signal_id: SignalId,
|
||||
/// The signal stood against.
|
||||
signal: Signal,
|
||||
/// The account which stood against the signal.
|
||||
who: SeraiAddress,
|
||||
for_network: NetworkId,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
use frame_support::dispatch::{DispatchInfo, DispatchError};
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use serai_primitives::SeraiAddress;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
/// An event from the system.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Event {
|
||||
ExtrinsicSuccess { dispatch_info: DispatchInfo },
|
||||
ExtrinsicFailed { dispatch_error: DispatchError, dispatch_info: DispatchInfo },
|
||||
CodeUpdated,
|
||||
NewAccount { account: SeraiAddress },
|
||||
KilledAccount { account: SeraiAddress },
|
||||
Remarked { sender: SeraiAddress, hash: [u8; 32] },
|
||||
/// The transaction successfully executed.
|
||||
TransactionSuccess,
|
||||
/// The transaction failed to execute.
|
||||
// TODO: Add an error to this
|
||||
TransactionFailed,
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
pub enum Call {
|
||||
set {
|
||||
#[codec(compact)]
|
||||
now: u64,
|
||||
},
|
||||
}
|
||||
319
substrate/abi/src/transaction.rs
Normal file
319
substrate/abi/src/transaction.rs
Normal file
@@ -0,0 +1,319 @@
|
||||
use core::num::NonZero;
|
||||
use alloc::{vec, vec::Vec};
|
||||
|
||||
use borsh::{io, BorshSerialize, BorshDeserialize};
|
||||
|
||||
use serai_primitives::{address::SeraiAddress, crypto::Signature};
|
||||
use crate::Call;
|
||||
|
||||
// use frame_support::dispatch::GetDispatchInfo;
|
||||
|
||||
/// An error regarding `SignedCalls`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum SignedCallsError {
|
||||
/// No calls were included.
|
||||
NoCalls,
|
||||
/// An unsigned call was included.
|
||||
IncludedUnsignedCall,
|
||||
}
|
||||
|
||||
/// A `Vec` of signed calls.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct SignedCalls(Vec<Call>);
|
||||
impl TryFrom<Vec<Call>> for SignedCalls {
|
||||
type Error = SignedCallsError;
|
||||
fn try_from(calls: Vec<Call>) -> Result<Self, Self::Error> {
|
||||
if calls.is_empty() {
|
||||
Err(SignedCallsError::NoCalls)?;
|
||||
}
|
||||
for call in &calls {
|
||||
if !call.is_signed() {
|
||||
Err(SignedCallsError::IncludedUnsignedCall)?;
|
||||
}
|
||||
}
|
||||
Ok(SignedCalls(calls))
|
||||
}
|
||||
}
|
||||
|
||||
/// An error regarding `UnsignedCall`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum UnsignedCallError {
|
||||
/// A signed call was specified.
|
||||
SignedCall,
|
||||
}
|
||||
|
||||
/// An unsigned call.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct UnsignedCall(Call);
|
||||
impl TryFrom<Call> for UnsignedCall {
|
||||
type Error = UnsignedCallError;
|
||||
fn try_from(call: Call) -> Result<Self, Self::Error> {
|
||||
if call.is_signed() {
|
||||
Err(UnsignedCallError::SignedCall)?;
|
||||
}
|
||||
Ok(UnsignedCall(call))
|
||||
}
|
||||
}
|
||||
|
||||
/// Part of the context used to sign with, from the protocol.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct ImplicitContext {
|
||||
/// The ID of the the protocol.
|
||||
pub protocol_id: [u8; 32],
|
||||
/// The genesis hash of the blockchain.
|
||||
pub genesis: [u8; 32],
|
||||
}
|
||||
|
||||
/// Part of the context used to sign with, specified within the transaction itself.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct ExplicitContext {
|
||||
/// The historic block this transaction builds upon.
|
||||
///
|
||||
/// This transaction can not be included in a blockchain which does not include this block.
|
||||
pub historic_block: [u8; 32],
|
||||
|
||||
/// The block this transaction expires at.
|
||||
///
|
||||
/// This transaction can not be included in a block whose number is equal or greater to this
|
||||
/// value.
|
||||
pub expires_at: Option<NonZero<u64>>,
|
||||
|
||||
/// The signer.
|
||||
pub signer: SeraiAddress,
|
||||
|
||||
/// The signer's nonce.
|
||||
pub nonce: u32,
|
||||
|
||||
/// The fee paid to the network for inclusion.
|
||||
///
|
||||
/// This fee is paid regardless of the success of any of the calls.
|
||||
pub fee: u64,
|
||||
}
|
||||
|
||||
/// A signature, with context.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct ContextualizedSignature {
|
||||
/// The explicit context.
|
||||
explicit_context: ExplicitContext,
|
||||
/// The signature.
|
||||
signature: Signature,
|
||||
}
|
||||
|
||||
/// The Serai transaction type.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Transaction<RuntimeCall: 'static + From<Call> = Call> {
|
||||
/// The calls, as defined in Serai's ABI.
|
||||
///
|
||||
/// These calls are executed atomically. Either all successfully execute or none do. The
|
||||
/// transaction's fee is paid regardless.
|
||||
// TODO: Bound
|
||||
calls: Vec<Call>,
|
||||
/// The calls, as defined by Substrate.
|
||||
runtime_calls: Vec<RuntimeCall>,
|
||||
/// The signature, if present.
|
||||
contextualized_signature: Option<ContextualizedSignature>,
|
||||
}
|
||||
|
||||
impl<RuntimeCall: 'static + From<Call>> BorshSerialize for Transaction<RuntimeCall> {
|
||||
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
||||
// Write the calls
|
||||
self.calls.serialize(writer)?;
|
||||
// Write the signature, if present. Presence is deterministic to the calls
|
||||
if let Some(contextualized_signature) = self.contextualized_signature.as_ref() {
|
||||
contextualized_signature.serialize(writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall: 'static + From<Call>> BorshDeserialize for Transaction<RuntimeCall> {
|
||||
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
|
||||
// Read the calls
|
||||
let calls = Vec::<Call>::deserialize_reader(reader)?;
|
||||
// Populate the runtime calls
|
||||
let mut runtime_calls = Vec::with_capacity(calls.len());
|
||||
for call in calls.iter().cloned() {
|
||||
runtime_calls.push(RuntimeCall::from(call));
|
||||
}
|
||||
|
||||
// Determine if this is signed or unsigned
|
||||
let mut signed = None;
|
||||
for call in &calls {
|
||||
let call_is_signed = call.is_signed();
|
||||
if signed.is_none() {
|
||||
signed = Some(call_is_signed)
|
||||
};
|
||||
if signed != Some(call_is_signed) {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "calls were a mixture of signed and unsigned"))?;
|
||||
}
|
||||
}
|
||||
let Some(signed) = signed else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "transaction had no calls"))?
|
||||
};
|
||||
|
||||
// Read the signature, if these calls are signed
|
||||
let contextualized_signature =
|
||||
if signed { Some(<ContextualizedSignature>::deserialize_reader(reader)?) } else { None };
|
||||
|
||||
Ok(Transaction { calls, runtime_calls, contextualized_signature })
|
||||
}
|
||||
}
|
||||
|
||||
impl<RuntimeCall: 'static + From<Call>> Transaction<RuntimeCall> {
|
||||
/// The message to sign to produce a signature.
|
||||
pub fn signature_message(
|
||||
calls: &SignedCalls,
|
||||
implicit_context: &ImplicitContext,
|
||||
explicit_context: &ExplicitContext,
|
||||
) -> Vec<u8> {
|
||||
let mut message = Vec::with_capacity(
|
||||
(calls.0.len() * 64) +
|
||||
core::mem::size_of::<ImplicitContext>() +
|
||||
core::mem::size_of::<ExplicitContext>(),
|
||||
);
|
||||
calls.0.serialize(&mut message).unwrap();
|
||||
implicit_context.serialize(&mut message).unwrap();
|
||||
explicit_context.serialize(&mut message).unwrap();
|
||||
message
|
||||
}
|
||||
|
||||
/// A transaction with signed calls.
|
||||
pub fn is_signed(
|
||||
calls: SignedCalls,
|
||||
explicit_context: ExplicitContext,
|
||||
signature: Signature,
|
||||
) -> Self {
|
||||
let calls = calls.0;
|
||||
let mut runtime_calls = Vec::with_capacity(calls.len());
|
||||
for call in calls.iter().cloned() {
|
||||
runtime_calls.push(call.into());
|
||||
}
|
||||
Self {
|
||||
calls,
|
||||
runtime_calls,
|
||||
contextualized_signature: Some(ContextualizedSignature { explicit_context, signature }),
|
||||
}
|
||||
}
|
||||
|
||||
/// A transaction with an unsigned call.
|
||||
pub fn unsigned(call: UnsignedCall) -> Self {
|
||||
let call = call.0;
|
||||
Self {
|
||||
calls: vec![call.clone()],
|
||||
runtime_calls: vec![call.into()],
|
||||
contextualized_signature: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "substrate")]
|
||||
mod substrate {
|
||||
use super::*;
|
||||
|
||||
impl scale::Encode for Transaction {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
borsh::to_vec(self).unwrap()
|
||||
}
|
||||
}
|
||||
impl scale::Decode for Transaction {
|
||||
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||
struct ScaleRead<'a, I: scale::Input>(&'a mut I);
|
||||
impl<I: scale::Input> borsh::io::Read for ScaleRead<'_, I> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> borsh::io::Result<usize> {
|
||||
let remaining_len = self
|
||||
.0
|
||||
.remaining_len()
|
||||
.map_err(|err| borsh::io::Error::new(borsh::io::ErrorKind::Other, err))?;
|
||||
// If we're still calling `read`, we try to read at least one more byte
|
||||
let to_read = buf.len().min(remaining_len.unwrap_or(1));
|
||||
self
|
||||
.0
|
||||
.read(&mut buf[.. to_read])
|
||||
.map_err(|err| borsh::io::Error::new(borsh::io::ErrorKind::Other, err))?;
|
||||
Ok(to_read)
|
||||
}
|
||||
}
|
||||
Self::deserialize_reader(&mut ScaleRead(input)).map_err(|err| err.downcast().unwrap())
|
||||
}
|
||||
}
|
||||
impl<RuntimeCall: 'static + From<Call>> sp_runtime::traits::ExtrinsicLike
|
||||
for Transaction<RuntimeCall>
|
||||
{
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
Some(self.calls[0].is_signed())
|
||||
}
|
||||
fn is_bare(&self) -> bool {
|
||||
!self.calls[0].is_signed()
|
||||
}
|
||||
}
|
||||
/*
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<Call> + TryInto<Call>,
|
||||
> sp_runtime::traits::Extrinsic for Transaction<Call>
|
||||
{
|
||||
type Call = Call;
|
||||
type SignaturePayload = (SeraiAddress, Signature, Extra);
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
Some(self.signature.is_some())
|
||||
}
|
||||
fn new(call: Call, signature: Option<Self::SignaturePayload>) -> Option<Self> {
|
||||
Some(Self { call: call.clone().try_into().ok()?, mapped_call: call, signature })
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call> + TryInto<crate::Call>,
|
||||
> frame_support::traits::ExtrinsicCall for Transaction<Call, Extra>
|
||||
{
|
||||
fn call(&self) -> &Call {
|
||||
&self.mapped_call
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
> sp_runtime::traits::ExtrinsicMetadata for Transaction<Call, Extra>
|
||||
{
|
||||
type SignedExtensions = Extra;
|
||||
|
||||
const VERSION: u8 = 0;
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call> + GetDispatchInfo,
|
||||
> GetDispatchInfo for Transaction<Call, Extra>
|
||||
{
|
||||
fn get_dispatch_info(&self) -> frame_support::dispatch::DispatchInfo {
|
||||
self.mapped_call.get_dispatch_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
> sp_runtime::traits::BlindCheckable for Transaction<Call, Extra>
|
||||
{
|
||||
type Checked = sp_runtime::generic::CheckedExtrinsic<Public, Call, Extra>;
|
||||
|
||||
fn check(
|
||||
self,
|
||||
) -> Result<Self::Checked, sp_runtime::transaction_validity::TransactionValidityError> {
|
||||
Ok(match self.signature {
|
||||
Some((signer, signature, extra)) => {
|
||||
if !signature.verify(
|
||||
(&self.call, &extra, extra.additional_signed()?).encode().as_slice(),
|
||||
&signer.into(),
|
||||
) {
|
||||
Err(sp_runtime::transaction_validity::InvalidTransaction::BadProof)?
|
||||
}
|
||||
|
||||
sp_runtime::generic::CheckedExtrinsic {
|
||||
signed: Some((signer.into(), extra)),
|
||||
function: self.mapped_call,
|
||||
}
|
||||
}
|
||||
None => sp_runtime::generic::CheckedExtrinsic { signed: None, function: self.mapped_call },
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
use scale::Encode;
|
||||
|
||||
use sp_core::sr25519::{Public, Signature};
|
||||
use sp_runtime::traits::Verify;
|
||||
|
||||
use serai_primitives::SeraiAddress;
|
||||
|
||||
use frame_support::dispatch::GetDispatchInfo;
|
||||
|
||||
pub trait TransactionMember:
|
||||
Clone + PartialEq + Eq + core::fmt::Debug + scale::Encode + scale::Decode + scale_info::TypeInfo
|
||||
{
|
||||
}
|
||||
impl<
|
||||
T: Clone
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ core::fmt::Debug
|
||||
+ scale::Encode
|
||||
+ scale::Decode
|
||||
+ scale_info::TypeInfo,
|
||||
> TransactionMember for T
|
||||
{
|
||||
}
|
||||
|
||||
type TransactionEncodeAs<'a, Extra> =
|
||||
(&'a crate::Call, &'a Option<(SeraiAddress, Signature, Extra)>);
|
||||
type TransactionDecodeAs<Extra> = (crate::Call, Option<(SeraiAddress, Signature, Extra)>);
|
||||
|
||||
// We use our own Transaction struct, over UncheckedExtrinsic, for more control, a bit more
|
||||
// simplicity, and in order to be immune to https://github.com/paritytech/polkadot-sdk/issues/2947
|
||||
#[allow(private_bounds)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Transaction<
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
Extra: 'static + TransactionMember,
|
||||
> {
|
||||
call: crate::Call,
|
||||
mapped_call: Call,
|
||||
signature: Option<(SeraiAddress, Signature, Extra)>,
|
||||
}
|
||||
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
Transaction<Call, Extra>
|
||||
{
|
||||
pub fn new(call: crate::Call, signature: Option<(SeraiAddress, Signature, Extra)>) -> Self {
|
||||
Self { call: call.clone(), mapped_call: call.into(), signature }
|
||||
}
|
||||
|
||||
pub fn call(&self) -> &crate::Call {
|
||||
&self.call
|
||||
}
|
||||
}
|
||||
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
scale::Encode for Transaction<Call, Extra>
|
||||
{
|
||||
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||
let tx: TransactionEncodeAs<Extra> = (&self.call, &self.signature);
|
||||
tx.using_encoded(f)
|
||||
}
|
||||
}
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
scale::Decode for Transaction<Call, Extra>
|
||||
{
|
||||
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||
let (call, signature) = TransactionDecodeAs::decode(input)?;
|
||||
let mapped_call = Call::from(call.clone());
|
||||
Ok(Self { call, mapped_call, signature })
|
||||
}
|
||||
}
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
scale_info::TypeInfo for Transaction<Call, Extra>
|
||||
{
|
||||
type Identity = TransactionDecodeAs<Extra>;
|
||||
|
||||
// Define the type info as the info of the type equivalent to what we encode as
|
||||
fn type_info() -> scale_info::Type {
|
||||
TransactionDecodeAs::<Extra>::type_info()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
mod _serde {
|
||||
use scale::Encode;
|
||||
use serde::ser::*;
|
||||
use super::*;
|
||||
impl<Call: 'static + TransactionMember + From<crate::Call>, Extra: 'static + TransactionMember>
|
||||
Serialize for Transaction<Call, Extra>
|
||||
{
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let encoded = self.encode();
|
||||
serializer.serialize_bytes(&encoded)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use serde::de::*;
|
||||
#[cfg(feature = "std")]
|
||||
impl<
|
||||
'a,
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
Extra: 'static + TransactionMember,
|
||||
> Deserialize<'a> for Transaction<Call, Extra>
|
||||
{
|
||||
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
|
||||
let bytes = sp_core::bytes::deserialize(de)?;
|
||||
<Self as scale::Decode>::decode(&mut &bytes[..])
|
||||
.map_err(|e| serde::de::Error::custom(format!("invalid transaction: {e}")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call> + TryInto<crate::Call>,
|
||||
Extra: 'static + TransactionMember,
|
||||
> sp_runtime::traits::Extrinsic for Transaction<Call, Extra>
|
||||
{
|
||||
type Call = Call;
|
||||
type SignaturePayload = (SeraiAddress, Signature, Extra);
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
Some(self.signature.is_some())
|
||||
}
|
||||
fn new(call: Call, signature: Option<Self::SignaturePayload>) -> Option<Self> {
|
||||
Some(Self { call: call.clone().try_into().ok()?, mapped_call: call, signature })
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call> + TryInto<crate::Call>,
|
||||
Extra: 'static + TransactionMember,
|
||||
> frame_support::traits::ExtrinsicCall for Transaction<Call, Extra>
|
||||
{
|
||||
fn call(&self) -> &Call {
|
||||
&self.mapped_call
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
Extra: 'static + TransactionMember + sp_runtime::traits::SignedExtension,
|
||||
> sp_runtime::traits::ExtrinsicMetadata for Transaction<Call, Extra>
|
||||
{
|
||||
type SignedExtensions = Extra;
|
||||
|
||||
const VERSION: u8 = 0;
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call> + GetDispatchInfo,
|
||||
Extra: 'static + TransactionMember,
|
||||
> GetDispatchInfo for Transaction<Call, Extra>
|
||||
{
|
||||
fn get_dispatch_info(&self) -> frame_support::dispatch::DispatchInfo {
|
||||
self.mapped_call.get_dispatch_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Call: 'static + TransactionMember + From<crate::Call>,
|
||||
Extra: 'static + TransactionMember + sp_runtime::traits::SignedExtension,
|
||||
> sp_runtime::traits::BlindCheckable for Transaction<Call, Extra>
|
||||
{
|
||||
type Checked = sp_runtime::generic::CheckedExtrinsic<Public, Call, Extra>;
|
||||
|
||||
fn check(
|
||||
self,
|
||||
) -> Result<Self::Checked, sp_runtime::transaction_validity::TransactionValidityError> {
|
||||
Ok(match self.signature {
|
||||
Some((signer, signature, extra)) => {
|
||||
if !signature.verify(
|
||||
(&self.call, &extra, extra.additional_signed()?).encode().as_slice(),
|
||||
&signer.into(),
|
||||
) {
|
||||
Err(sp_runtime::transaction_validity::InvalidTransaction::BadProof)?
|
||||
}
|
||||
|
||||
sp_runtime::generic::CheckedExtrinsic {
|
||||
signed: Some((signer.into(), extra)),
|
||||
function: self.mapped_call,
|
||||
}
|
||||
}
|
||||
None => sp_runtime::generic::CheckedExtrinsic { signed: None, function: self.mapped_call },
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,79 +1,144 @@
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use sp_core::{ConstU32, bounded::BoundedVec};
|
||||
|
||||
pub use serai_validator_sets_primitives as primitives;
|
||||
use serai_primitives::{
|
||||
crypto::{ExternalKey, KeyPair, Signature},
|
||||
address::SeraiAddress,
|
||||
balance::Amount,
|
||||
network_id::*,
|
||||
validator_sets::*,
|
||||
};
|
||||
|
||||
use serai_primitives::*;
|
||||
use serai_validator_sets_primitives::*;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
/// A call to the validator sets.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Call {
|
||||
/// Set the keys for a validator set.
|
||||
set_keys {
|
||||
/// The network whose latest validator set is setting their keys.
|
||||
network: ExternalNetworkId,
|
||||
/// The keys being set.
|
||||
key_pair: KeyPair,
|
||||
/// The participants in the validator set who signed off on these keys.
|
||||
#[borsh(
|
||||
serialize_with = "serai_primitives::sp_borsh::borsh_serialize_bitvec",
|
||||
deserialize_with = "serai_primitives::sp_borsh::borsh_deserialize_bitvec"
|
||||
)]
|
||||
signature_participants: bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
|
||||
/// The signature confirming these keys are valid.
|
||||
signature: Signature,
|
||||
},
|
||||
set_embedded_elliptic_curve_key {
|
||||
embedded_elliptic_curve: EmbeddedEllipticCurve,
|
||||
key: BoundedVec<u8, ConstU32<{ MAX_KEY_LEN }>>,
|
||||
},
|
||||
/// Report a validator set's slashes onto Serai.
|
||||
report_slashes {
|
||||
/// The network whose retiring validator set is setting their keys.
|
||||
network: ExternalNetworkId,
|
||||
/// The slashes they're reporting.
|
||||
slashes: SlashReport,
|
||||
/// The signature confirming the validity of this slash report.
|
||||
signature: Signature,
|
||||
},
|
||||
/// Set a validator's keys on embedded elliptic curves for a specific network.
|
||||
set_embedded_elliptic_curve_keys {
|
||||
/// The network the origin is setting their embedded elliptic curve keys for.
|
||||
network: ExternalNetworkId,
|
||||
/// The keys on the embedded elliptic curves.
|
||||
///
|
||||
/// This may be a single key if the external network uses the same embedded elliptic curve as
|
||||
/// used for the key to oraclize onto Serai.
|
||||
#[borsh(
|
||||
serialize_with = "serai_primitives::sp_borsh::borsh_serialize_bounded_vec",
|
||||
deserialize_with = "serai_primitives::sp_borsh::borsh_deserialize_bounded_vec"
|
||||
)]
|
||||
keys: BoundedVec<u8, ConstU32<{ 2 * ExternalKey::MAX_LEN }>>,
|
||||
},
|
||||
/// Allocate stake to a network.
|
||||
allocate {
|
||||
/// The network to allocate stake to.
|
||||
network: NetworkId,
|
||||
/// The amount of stake to allocate.
|
||||
amount: Amount,
|
||||
},
|
||||
/// Deallocate stake from a network.
|
||||
///
|
||||
/// This deallocation may be immediate or may be delayed depending on if the origin is an
|
||||
/// active, or even recent, validator. If delayed, it will have to be claimed at a later time.
|
||||
deallocate {
|
||||
/// The network to deallocate stake from.
|
||||
network: NetworkId,
|
||||
/// The amount of stake to deallocate.
|
||||
amount: Amount,
|
||||
},
|
||||
/// Claim a now-unlocked deallocation.
|
||||
claim_deallocation {
|
||||
network: NetworkId,
|
||||
session: Session,
|
||||
/// The validator set which claiming the deallocation was delayed until.
|
||||
deallocation: ValidatorSet,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, scale::Encode, scale::Decode, scale_info::TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
|
||||
#[cfg_attr(all(feature = "std", feature = "serde"), derive(serde::Deserialize))]
|
||||
impl Call {
|
||||
pub(crate) fn is_signed(&self) -> bool {
|
||||
match self {
|
||||
Call::set_keys { .. } | Call::report_slashes { .. } => false,
|
||||
Call::set_embedded_elliptic_curve_keys { .. } |
|
||||
Call::allocate { .. } |
|
||||
Call::deallocate { .. } |
|
||||
Call::claim_deallocation { .. } => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event from the validator sets.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Event {
|
||||
/// A new validator set was declared.
|
||||
NewSet {
|
||||
/// The set declared.
|
||||
set: ValidatorSet,
|
||||
},
|
||||
ParticipantRemoved {
|
||||
set: ValidatorSet,
|
||||
removed: SeraiAddress,
|
||||
},
|
||||
KeyGen {
|
||||
/// A validator set has set their keys.
|
||||
SetKeys {
|
||||
/// The set which set their keys.
|
||||
set: ExternalValidatorSet,
|
||||
/// The keys sets.
|
||||
key_pair: KeyPair,
|
||||
},
|
||||
/// A validator set has accepted responsibility from the prior validator set.
|
||||
AcceptedHandover {
|
||||
/// The set which accepted responsibility from the prior set.
|
||||
set: ValidatorSet,
|
||||
},
|
||||
/// A validator set has retired.
|
||||
SetRetired {
|
||||
/// The set retired.
|
||||
set: ValidatorSet,
|
||||
},
|
||||
AllocationIncreased {
|
||||
/// A validator's allocation to a network has increased.
|
||||
Allocation {
|
||||
/// The validator who increased their allocation.
|
||||
validator: SeraiAddress,
|
||||
/// The network the stake was allocated to.
|
||||
network: NetworkId,
|
||||
/// The amount of stake allocated.
|
||||
amount: Amount,
|
||||
},
|
||||
AllocationDecreased {
|
||||
/// A validator's allocation to a network has decreased.
|
||||
Deallocation {
|
||||
/// The validator who decreased their allocation.
|
||||
validator: SeraiAddress,
|
||||
/// The network the stake was deallocated from.
|
||||
network: NetworkId,
|
||||
/// The amount of stake deallocated.
|
||||
amount: Amount,
|
||||
/// The session which claiming the deallocation was delayed until.
|
||||
delayed_until: Option<Session>,
|
||||
},
|
||||
/// A validator's deallocation from a network has been claimed.
|
||||
///
|
||||
/// This is only emited for deallocations which were delayed and has to be explicitly claimed.
|
||||
DeallocationClaimed {
|
||||
/// The validator who claimed their deallocation.
|
||||
validator: SeraiAddress,
|
||||
network: NetworkId,
|
||||
session: Session,
|
||||
/// The validator set the deallocation was delayed until.
|
||||
deallocation: ValidatorSet,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,54 +1 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use serai_primitives::{ExternalBalance, SeraiAddress, ExternalAddress, system_address};
|
||||
|
||||
pub const FEE_ACCOUNT: SeraiAddress = system_address(b"Coins-fees");
|
||||
|
||||
// TODO: Replace entirely with just Address
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct OutInstruction {
|
||||
pub address: ExternalAddress,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct OutInstructionWithBalance {
|
||||
pub instruction: OutInstruction,
|
||||
pub balance: ExternalBalance,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum Destination {
|
||||
Native(SeraiAddress),
|
||||
External(OutInstruction),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn address() {
|
||||
use sp_runtime::traits::TrailingZeroInput;
|
||||
assert_eq!(
|
||||
FEE_ACCOUNT,
|
||||
SeraiAddress::decode(&mut TrailingZeroInput::new(b"Coins-fees")).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,54 +1 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use serai_primitives::*;
|
||||
use validator_sets_primitives::ValidatorSet;
|
||||
|
||||
pub const INITIAL_GENESIS_LP_SHARES: u64 = 10_000;
|
||||
|
||||
// This is the account to hold and manage the genesis liquidity.
|
||||
pub const GENESIS_LIQUIDITY_ACCOUNT: SeraiAddress = system_address(b"GenesisLiquidity-account");
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Values {
|
||||
pub monero: u64,
|
||||
pub ether: u64,
|
||||
pub dai: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct LiquidityAmount {
|
||||
pub shares: u64,
|
||||
pub coins: u64,
|
||||
}
|
||||
|
||||
impl LiquidityAmount {
|
||||
pub fn zero() -> Self {
|
||||
LiquidityAmount { shares: 0, coins: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
/// The message for the oraclize_values signature.
|
||||
pub fn oraclize_values_message(set: &ValidatorSet, values: &Values) -> Vec<u8> {
|
||||
(b"GenesisLiquidity-oraclize_values", set, values).encode()
|
||||
}
|
||||
|
||||
@@ -1,141 +1 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use sp_application_crypto::sr25519::Signature;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use sp_std::vec::Vec;
|
||||
use sp_runtime::RuntimeDebug;
|
||||
|
||||
#[rustfmt::skip]
|
||||
use serai_primitives::{BlockHash, ExternalNetworkId, NetworkId, ExternalBalance, Balance, SeraiAddress, ExternalAddress, system_address};
|
||||
|
||||
mod shorthand;
|
||||
pub use shorthand::*;
|
||||
|
||||
pub const MAX_BATCH_SIZE: usize = 25_000; // ~25kb
|
||||
|
||||
// This is the account which will be the origin for any dispatched `InInstruction`s.
|
||||
pub const IN_INSTRUCTION_EXECUTOR: SeraiAddress = system_address(b"InInstructions-executor");
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum OutAddress {
|
||||
Serai(SeraiAddress),
|
||||
External(ExternalAddress),
|
||||
}
|
||||
|
||||
impl OutAddress {
|
||||
pub fn is_native(&self) -> bool {
|
||||
matches!(self, Self::Serai(_))
|
||||
}
|
||||
|
||||
pub fn as_native(self) -> Option<SeraiAddress> {
|
||||
match self {
|
||||
Self::Serai(addr) => Some(addr),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_external(self) -> Option<ExternalAddress> {
|
||||
match self {
|
||||
Self::External(addr) => Some(addr),
|
||||
Self::Serai(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum DexCall {
|
||||
// address to send the lp tokens to
|
||||
// TODO: Update this per documentation/Shorthand
|
||||
SwapAndAddLiquidity(SeraiAddress),
|
||||
// minimum out balance and out address
|
||||
Swap(Balance, OutAddress),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum InInstruction {
|
||||
Transfer(SeraiAddress),
|
||||
Dex(DexCall),
|
||||
GenesisLiquidity(SeraiAddress),
|
||||
SwapToStakedSRI(SeraiAddress, NetworkId),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct RefundableInInstruction {
|
||||
pub origin: Option<ExternalAddress>,
|
||||
pub instruction: InInstruction,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct InInstructionWithBalance {
|
||||
pub instruction: InInstruction,
|
||||
pub balance: ExternalBalance,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo, RuntimeDebug)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Batch {
|
||||
pub network: ExternalNetworkId,
|
||||
pub id: u32,
|
||||
pub external_network_block_hash: BlockHash,
|
||||
pub instructions: Vec<InInstructionWithBalance>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo, RuntimeDebug)]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct SignedBatch {
|
||||
pub batch: Batch,
|
||||
#[cfg_attr(
|
||||
feature = "borsh",
|
||||
borsh(
|
||||
serialize_with = "serai_primitives::borsh_serialize_signature",
|
||||
deserialize_with = "serai_primitives::borsh_deserialize_signature"
|
||||
)
|
||||
)]
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Zeroize for SignedBatch {
|
||||
fn zeroize(&mut self) {
|
||||
self.batch.zeroize();
|
||||
self.signature.as_mut().zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make this an associated method?
|
||||
/// The message for the batch signature.
|
||||
pub fn batch_message(batch: &Batch) -> Vec<u8> {
|
||||
[b"InInstructions-batch".as_ref(), &batch.encode()].concat()
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use serai_primitives::{Amount, ExternalAddress, ExternalCoin, SeraiAddress};
|
||||
|
||||
use coins_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(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum Shorthand {
|
||||
Raw(RefundableInInstruction),
|
||||
Swap {
|
||||
origin: Option<ExternalAddress>,
|
||||
coin: ExternalCoin,
|
||||
minimum: Amount,
|
||||
out: OutInstruction,
|
||||
},
|
||||
SwapAndAddLiquidity {
|
||||
origin: Option<ExternalAddress>,
|
||||
minimum: Amount,
|
||||
gas: Amount,
|
||||
address: SeraiAddress,
|
||||
},
|
||||
}
|
||||
|
||||
impl Shorthand {
|
||||
#[cfg(feature = "std")]
|
||||
pub fn transfer(origin: Option<ExternalAddress>, address: SeraiAddress) -> Self {
|
||||
Self::Raw(RefundableInInstruction { origin, instruction: InInstruction::Transfer(address) })
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Shorthand> for RefundableInInstruction {
|
||||
type Error = &'static str;
|
||||
fn try_from(shorthand: Shorthand) -> Result<RefundableInInstruction, &'static str> {
|
||||
Ok(match shorthand {
|
||||
Shorthand::Raw(instruction) => instruction,
|
||||
Shorthand::Swap { .. } => todo!(),
|
||||
Shorthand::SwapAndAddLiquidity { .. } => todo!(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -16,29 +16,19 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
zeroize = { version = "^1.5", features = ["derive"], optional = true }
|
||||
zeroize = { version = "^1.5", features = ["derive"] }
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"] }
|
||||
|
||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, optional = true }
|
||||
|
||||
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "2", default-features = false, features = ["derive"] }
|
||||
|
||||
borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true }
|
||||
serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true }
|
||||
|
||||
sp-application-crypto = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
bitvec = { version = "1", default-features = false, features = ["alloc"] }
|
||||
sp-core = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
sp-runtime = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
sp-io = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
sp-std = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
|
||||
frame-support = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["alloc", "ristretto"] }
|
||||
dkg = { path = "../../crypto/dkg", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
|
||||
bech32 = { version = "0.11", default-features = false }
|
||||
|
||||
[features]
|
||||
std = ["zeroize", "ciphersuite/std", "scale/std", "borsh?/std", "serde?/std", "scale-info/std", "sp-core/std", "sp-runtime/std", "sp-std/std", "frame-support/std"]
|
||||
borsh = ["dep:borsh"]
|
||||
serde = ["dep:serde"]
|
||||
std = ["zeroize/std", "borsh/std", "ciphersuite/std", "dkg/std", "sp-core/std", "bech32/std"]
|
||||
default = ["std"]
|
||||
borsh = [] # TODO
|
||||
serde = [] # TODO
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2023 Luke Parker
|
||||
Copyright (c) 2022-2025 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
|
||||
|
||||
4
substrate/primitives/README.md
Normal file
4
substrate/primitives/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Serai Primitives
|
||||
|
||||
`serai-primitives` represents foundational data-types used within Serai's
|
||||
Substrate blockchain.
|
||||
@@ -1,144 +0,0 @@
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use sp_core::sr25519::Public;
|
||||
pub use sp_core::sr25519::Signature;
|
||||
#[cfg(feature = "std")]
|
||||
use sp_core::{Pair as PairTrait, sr25519::Pair};
|
||||
|
||||
use sp_runtime::traits::{LookupError, Lookup, StaticLookup};
|
||||
|
||||
pub type PublicKey = Public;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
pub fn borsh_serialize_public<W: borsh::io::Write>(
|
||||
public: &Public,
|
||||
writer: &mut W,
|
||||
) -> Result<(), borsh::io::Error> {
|
||||
borsh::BorshSerialize::serialize(&public.0, writer)
|
||||
}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
pub fn borsh_deserialize_public<R: borsh::io::Read>(
|
||||
reader: &mut R,
|
||||
) -> Result<Public, borsh::io::Error> {
|
||||
let public: [u8; 32] = borsh::BorshDeserialize::deserialize_reader(reader)?;
|
||||
Ok(Public(public))
|
||||
}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
pub fn borsh_serialize_signature<W: borsh::io::Write>(
|
||||
signature: &Signature,
|
||||
writer: &mut W,
|
||||
) -> Result<(), borsh::io::Error> {
|
||||
borsh::BorshSerialize::serialize(&signature.0, writer)
|
||||
}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
pub fn borsh_deserialize_signature<R: borsh::io::Read>(
|
||||
reader: &mut R,
|
||||
) -> Result<Signature, borsh::io::Error> {
|
||||
let signature: [u8; 64] = borsh::BorshDeserialize::deserialize_reader(reader)?;
|
||||
Ok(Signature(signature))
|
||||
}
|
||||
|
||||
// TODO: Remove this for solely Public?
|
||||
#[derive(
|
||||
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", 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<PublicKey> for SeraiAddress {
|
||||
fn from(key: PublicKey) -> SeraiAddress {
|
||||
SeraiAddress(key.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SeraiAddress> 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a Substraate key pair by a name.
|
||||
///
|
||||
/// This should never be considered to have a secure private key. It has effectively no entropy.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn insecure_pair_from_name(name: &str) -> Pair {
|
||||
Pair::from_string(&format!("//{name}"), None).unwrap()
|
||||
}
|
||||
|
||||
/// Create a private key for an arbitrary ciphersuite by a name.
|
||||
///
|
||||
/// This key should never be considered a secure private key. It has effectively no entropy.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn insecure_arbitrary_key_from_name<C: ciphersuite::Ciphersuite>(name: &str) -> C::F {
|
||||
C::hash_to_F(b"insecure arbitrary key", name.as_bytes())
|
||||
}
|
||||
|
||||
pub struct AccountLookup;
|
||||
impl Lookup for AccountLookup {
|
||||
type Source = SeraiAddress;
|
||||
type Target = PublicKey;
|
||||
fn lookup(&self, source: SeraiAddress) -> Result<PublicKey, LookupError> {
|
||||
Ok(PublicKey::from_raw(source.0))
|
||||
}
|
||||
}
|
||||
impl StaticLookup for AccountLookup {
|
||||
type Source = SeraiAddress;
|
||||
type Target = PublicKey;
|
||||
fn lookup(source: SeraiAddress) -> Result<PublicKey, LookupError> {
|
||||
Ok(source.into())
|
||||
}
|
||||
fn unlookup(source: PublicKey) -> SeraiAddress {
|
||||
source.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn system_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)
|
||||
}
|
||||
143
substrate/primitives/src/address.rs
Normal file
143
substrate/primitives/src/address.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use sp_core::{sr25519::Public, ConstU32, bounded::BoundedVec};
|
||||
|
||||
/*
|
||||
We only use a single HRP across all networks. This follows Serai's general practice. Addresses
|
||||
for external networks are represented in binary, without network information. to minimize
|
||||
bandwidth and reduce potential for malleability.
|
||||
|
||||
This is continued here not solely to be a continuance, yet also with appreciation for the
|
||||
simplicity. This does make it easier for users to make the mistake of using a testnet address
|
||||
where they intended to use a mainnet address (and vice-versa). Since public keys are usable on
|
||||
any network, this should have limited impact and accordingly not be the end of the world.
|
||||
|
||||
There's also precedent for this due to Ethereum (though they do have a somewhat-adopted checksum
|
||||
scheme to encode the network regardless).
|
||||
*/
|
||||
const HUMAN_READABLE_PART: bech32::Hrp = bech32::Hrp::parse_unchecked("sri");
|
||||
|
||||
/// The address for an account on Serai.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct SeraiAddress(pub [u8; 32]);
|
||||
|
||||
impl SeraiAddress {
|
||||
/// Generate an address for use by the system.
|
||||
///
|
||||
/// The returned addresses MAY be valid points. This assumes its infeasible to find the discrete
|
||||
/// logarithm for a point whose representation has a known Blake2b-256 preimage.
|
||||
// The alternative would be to massage this until its not a valid point, which isn't worth the
|
||||
// computational expense as this should be a hard problem for outputs which happen to be points.
|
||||
pub fn system(label: &[u8]) -> Self {
|
||||
Self(sp_core::blake2_256(label))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Public> for SeraiAddress {
|
||||
fn from(key: Public) -> Self {
|
||||
// The encoding of a Ristretto point is the encoding of its address
|
||||
Self(key.0)
|
||||
}
|
||||
}
|
||||
/*
|
||||
A `SeraiAddress` may not be a valid public key. The `sr25519::Public` is not a checked public
|
||||
key, solely bytes alleged to be a public key, which any `SeraiAddress` converted into a `Public`
|
||||
is also alleged to be.
|
||||
*/
|
||||
impl From<SeraiAddress> for Public {
|
||||
fn from(address: SeraiAddress) -> Self {
|
||||
Self::from_raw(address.0)
|
||||
}
|
||||
}
|
||||
|
||||
// We use Bech32m to encode addresses
|
||||
impl core::fmt::Display for SeraiAddress {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match bech32::encode_to_fmt::<bech32::Bech32m, _>(f, HUMAN_READABLE_PART, &self.0) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(bech32::EncodeError::TooLong(_)) => {
|
||||
unreachable!("32 bytes exceeded bech32 length limit?")
|
||||
}
|
||||
Err(bech32::EncodeError::Fmt(e)) => Err(e),
|
||||
// bech32::EncodeError is non-exhaustive
|
||||
Err(_) => Err(core::fmt::Error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error from decoding an address.
|
||||
pub enum DecodeError {
|
||||
/// The Bech32m encoding was invalid.
|
||||
InvalidBech32m,
|
||||
/// The Bech32m Human-Readable Part was distinct.
|
||||
DistinctHrp,
|
||||
/// The encoded data's length was wrong.
|
||||
InvalidLength,
|
||||
}
|
||||
|
||||
impl core::str::FromStr for SeraiAddress {
|
||||
type Err = DecodeError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
// We drop bech32's error to remain opaque to the implementation
|
||||
let decoded = bech32::primitives::decode::CheckedHrpstring::new::<bech32::Bech32m>(s)
|
||||
.map_err(|_| DecodeError::InvalidBech32m)?;
|
||||
if decoded.hrp() != HUMAN_READABLE_PART {
|
||||
Err(DecodeError::DistinctHrp)?;
|
||||
}
|
||||
|
||||
let mut res = Self([0; 32]);
|
||||
let mut iter = decoded.byte_iter();
|
||||
for i in 0 .. 32 {
|
||||
let Some(byte) = iter.next() else { Err(DecodeError::InvalidLength)? };
|
||||
res.0[i] = byte;
|
||||
}
|
||||
if iter.next().is_some() {
|
||||
Err(DecodeError::InvalidLength)?;
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// An address for an external network.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, borsh::BorshSerialize, borsh::BorshDeserialize)]
|
||||
pub struct ExternalAddress(
|
||||
#[borsh(
|
||||
serialize_with = "crate::borsh_serialize_bounded_vec",
|
||||
deserialize_with = "crate::borsh_deserialize_bounded_vec"
|
||||
)]
|
||||
BoundedVec<u8, ConstU32<{ Self::MAX_LEN }>>,
|
||||
);
|
||||
|
||||
impl ExternalAddress {
|
||||
/// The maximum length for an `ExternalAddress`.
|
||||
pub const MAX_LEN: u32 = 512;
|
||||
}
|
||||
|
||||
/// An error when converting from a `Vec`.
|
||||
pub enum FromVecError {
|
||||
/// The source `Vec` was too long to be converted.
|
||||
TooLong,
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<u8>> for ExternalAddress {
|
||||
type Error = FromVecError;
|
||||
fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
|
||||
vec.try_into().map(ExternalAddress).map_err(|_| FromVecError::TooLong)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExternalAddress> for Vec<u8> {
|
||||
fn from(ext: ExternalAddress) -> Vec<u8> {
|
||||
ext.0.into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl zeroize::Zeroize for ExternalAddress {
|
||||
fn zeroize(&mut self) {
|
||||
self.0.as_mut().zeroize();
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
use core::{
|
||||
ops::{Add, Sub, Mul},
|
||||
fmt::Debug,
|
||||
};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
/// 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(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Amount(pub SubstrateAmount);
|
||||
|
||||
// TODO: these impl shouldn't panic and return error to be dealt with.
|
||||
// Otherwise we might have a panic that stops the network.
|
||||
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())
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,111 @@
|
||||
use core::ops::{Add, Sub, Mul};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
use crate::coin::{ExternalCoin, Coin};
|
||||
|
||||
use crate::{Amount, Coin, ExternalCoin};
|
||||
/// The type internally used to represent amounts.
|
||||
// https://github.com/rust-lang/rust/issues/8995
|
||||
pub type AmountRepr = u64;
|
||||
|
||||
/// The type used for balances (a Coin and Balance).
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Balance {
|
||||
pub coin: Coin,
|
||||
/// A wrapper used to represent amounts.
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Debug,
|
||||
Zeroize,
|
||||
BorshSerialize,
|
||||
BorshDeserialize,
|
||||
)]
|
||||
pub struct Amount(pub AmountRepr);
|
||||
|
||||
impl Add for Amount {
|
||||
type Output = Option<Amount>;
|
||||
fn add(self, other: Amount) -> Option<Amount> {
|
||||
self.0.checked_add(other.0).map(Amount)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for Amount {
|
||||
type Output = Option<Amount>;
|
||||
fn sub(self, other: Amount) -> Option<Amount> {
|
||||
self.0.checked_sub(other.0).map(Amount)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for Amount {
|
||||
type Output = Option<Amount>;
|
||||
fn mul(self, other: Amount) -> Option<Amount> {
|
||||
self.0.checked_mul(other.0).map(Amount)
|
||||
}
|
||||
}
|
||||
|
||||
/// An ExternalCoin and an Amount, forming a balance for an external coin.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct ExternalBalance {
|
||||
/// The coin this is a balance for.
|
||||
pub coin: ExternalCoin,
|
||||
/// The amount of this balance.
|
||||
pub amount: 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(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct ExternalBalance {
|
||||
pub coin: ExternalCoin,
|
||||
impl Add<Amount> for ExternalBalance {
|
||||
type Output = Option<ExternalBalance>;
|
||||
fn add(self, other: Amount) -> Option<ExternalBalance> {
|
||||
(self.amount + other).map(|amount| ExternalBalance { coin: self.coin, amount })
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Amount> for ExternalBalance {
|
||||
type Output = Option<ExternalBalance>;
|
||||
fn sub(self, other: Amount) -> Option<ExternalBalance> {
|
||||
(self.amount - other).map(|amount| ExternalBalance { coin: self.coin, amount })
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Amount> for ExternalBalance {
|
||||
type Output = Option<ExternalBalance>;
|
||||
fn mul(self, other: Amount) -> Option<ExternalBalance> {
|
||||
(self.amount * other).map(|amount| ExternalBalance { coin: self.coin, amount })
|
||||
}
|
||||
}
|
||||
|
||||
/// A Coin and an Amount, forming a balance for a coin.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Balance {
|
||||
/// The coin this is a balance for.
|
||||
pub coin: Coin,
|
||||
/// The amount of this balance.
|
||||
pub amount: Amount,
|
||||
}
|
||||
|
||||
impl Add<Amount> for Balance {
|
||||
type Output = Option<Balance>;
|
||||
fn add(self, other: Amount) -> Option<Balance> {
|
||||
(self.amount + other).map(|amount| Balance { coin: self.coin, amount })
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Amount> for Balance {
|
||||
type Output = Option<Balance>;
|
||||
fn sub(self, other: Amount) -> Option<Balance> {
|
||||
(self.amount - other).map(|amount| Balance { coin: self.coin, amount })
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Amount> for Balance {
|
||||
type Output = Option<Balance>;
|
||||
fn mul(self, other: Amount) -> Option<Balance> {
|
||||
(self.amount * other).map(|amount| Balance { coin: self.coin, amount })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExternalBalance> for Balance {
|
||||
fn from(balance: ExternalBalance) -> Self {
|
||||
Balance { coin: balance.coin.into(), amount: balance.amount }
|
||||
@@ -49,25 +122,3 @@ impl TryFrom<Balance> for ExternalBalance {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: these impl either should be removed or return errors in case of overflows
|
||||
impl Add<Amount> for Balance {
|
||||
type Output = Balance;
|
||||
fn add(self, other: Amount) -> Balance {
|
||||
Balance { coin: self.coin, amount: self.amount + other }
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Amount> for Balance {
|
||||
type Output = Balance;
|
||||
fn sub(self, other: Amount) -> Balance {
|
||||
Balance { coin: self.coin, amount: self.amount - other }
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Amount> for Balance {
|
||||
type Output = Balance;
|
||||
fn mul(self, other: Amount) -> Balance {
|
||||
Balance { coin: self.coin, amount: self.amount * other }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
use sp_core::H256;
|
||||
|
||||
/// The type used to identify block numbers.
|
||||
#[derive(
|
||||
Clone, Copy, Default, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct BlockNumber(pub u64);
|
||||
impl From<u64> for BlockNumber {
|
||||
fn from(number: u64) -> 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(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", 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<H256> for BlockHash {
|
||||
fn from(hash: H256) -> BlockHash {
|
||||
BlockHash(hash.into())
|
||||
}
|
||||
}
|
||||
118
substrate/primitives/src/coin.rs
Normal file
118
substrate/primitives/src/coin.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use borsh::{io, BorshSerialize, BorshDeserialize};
|
||||
|
||||
use crate::network_id::{ExternalNetworkId, NetworkId};
|
||||
|
||||
/// The type used to identify coins native to external networks.
|
||||
///
|
||||
/// This type serializes to a subset of `Coin`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
#[borsh(use_discriminant = true)]
|
||||
#[non_exhaustive]
|
||||
pub enum ExternalCoin {
|
||||
/// Bitcoin, from the Bitcoin network.
|
||||
Bitcoin = 1,
|
||||
/// Ether, from the Ethereum network.
|
||||
Ether = 2,
|
||||
/// Dai Stablecoin, from the Ethereum network.
|
||||
Dai = 3,
|
||||
/// Monero, from the Monero network.
|
||||
Monero = 4,
|
||||
}
|
||||
|
||||
impl ExternalCoin {
|
||||
/// All external coins.
|
||||
pub fn all() -> impl Iterator<Item = Self> {
|
||||
[ExternalCoin::Bitcoin, ExternalCoin::Ether, ExternalCoin::Dai, ExternalCoin::Monero]
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// The type used to identify coins.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize)]
|
||||
pub enum Coin {
|
||||
/// The Serai coin.
|
||||
Serai,
|
||||
/// An external coin.
|
||||
External(ExternalCoin),
|
||||
}
|
||||
|
||||
impl BorshSerialize for Coin {
|
||||
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
||||
match self {
|
||||
Self::Serai => writer.write_all(&[0]),
|
||||
Self::External(external) => external.serialize(writer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BorshDeserialize for Coin {
|
||||
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
|
||||
let mut kind = [0xff];
|
||||
reader.read_exact(&mut kind)?;
|
||||
match kind[0] {
|
||||
0 => Ok(Self::Serai),
|
||||
_ => ExternalCoin::deserialize_reader(&mut kind.as_slice()).map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Coin {
|
||||
/// All coins.
|
||||
pub fn all() -> impl Iterator<Item = Self> {
|
||||
core::iter::once(Coin::Serai).chain(ExternalCoin::all().map(Into::into))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExternalCoin> for Coin {
|
||||
fn from(coin: ExternalCoin) -> Self {
|
||||
Coin::External(coin)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Coin> for ExternalCoin {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(coin: Coin) -> Result<Self, Self::Error> {
|
||||
match coin {
|
||||
Coin::Serai => Err(())?,
|
||||
Coin::External(ext) => Ok(ext),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalCoin {
|
||||
/// The external network this coin is native to.
|
||||
pub fn network(&self) -> ExternalNetworkId {
|
||||
match self {
|
||||
ExternalCoin::Bitcoin => ExternalNetworkId::Bitcoin,
|
||||
ExternalCoin::Ether | ExternalCoin::Dai => ExternalNetworkId::Ethereum,
|
||||
ExternalCoin::Monero => ExternalNetworkId::Monero,
|
||||
}
|
||||
}
|
||||
|
||||
/// The decimals used for a single human unit of this coin.
|
||||
///
|
||||
/// This may be less than the decimals used for a single human unit of this coin *by defined
|
||||
/// convention*. If so, that means Serai is *truncating* the decimals. A coin which is defined
|
||||
/// as having 8 decimals, while Serai claims it has 4 decimals, will have `0.00019999`
|
||||
/// interpreted as `0.0001` (in human units, in atomic units, 19999 will be interpreted as 1).
|
||||
pub fn decimals(&self) -> u32 {
|
||||
match self {
|
||||
// Ether and DAI have 18 decimals, yet we only track 8 in order to fit them within u64s
|
||||
ExternalCoin::Bitcoin | ExternalCoin::Ether | ExternalCoin::Dai => 8,
|
||||
ExternalCoin::Monero => 12,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Coin {
|
||||
/// The network this coin is native to.
|
||||
pub fn network(&self) -> NetworkId {
|
||||
match self {
|
||||
Coin::Serai => NetworkId::Serai,
|
||||
Coin::External(c) => c.network().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,13 @@
|
||||
use crate::BlockNumber;
|
||||
use core::time::Duration;
|
||||
|
||||
// 1 MB
|
||||
pub const BLOCK_SIZE: u32 = 1024 * 1024;
|
||||
// 6 seconds
|
||||
// TODO: Use Duration
|
||||
pub const TARGET_BLOCK_TIME: u64 = 6;
|
||||
/// The target block time.
|
||||
pub const TARGET_BLOCK_TIME: Duration = Duration::from_secs(6);
|
||||
|
||||
/// Measured in blocks.
|
||||
pub const MINUTES: BlockNumber = 60 / TARGET_BLOCK_TIME;
|
||||
pub const HOURS: BlockNumber = 60 * MINUTES;
|
||||
pub const DAYS: BlockNumber = 24 * HOURS;
|
||||
pub const WEEKS: BlockNumber = 7 * DAYS;
|
||||
// Defines a month as 30 days, which is slightly inaccurate
|
||||
pub const MONTHS: BlockNumber = 30 * DAYS;
|
||||
// Defines a year as 12 inaccurate months, which is 360 days literally (~1.5% off)
|
||||
pub const YEARS: BlockNumber = 12 * MONTHS;
|
||||
/// The intended duration for a session.
|
||||
// 1 week
|
||||
pub const SESSION_LENGTH: Duration = Duration::from_secs(7 * 24 * 60 * 60);
|
||||
|
||||
/// 6 months of blocks
|
||||
pub const GENESIS_SRI_TRICKLE_FEED: u64 = 6 * MONTHS;
|
||||
|
||||
// 100 Million SRI
|
||||
pub const GENESIS_SRI: u64 = 100_000_000 * 10_u64.pow(8);
|
||||
|
||||
/// This needs to be long enough for arbitrage to occur and make holding any fake price up
|
||||
/// sufficiently unrealistic.
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
pub const ARBITRAGE_TIME: u16 = (2 * HOURS) as u16;
|
||||
|
||||
/// Since we use the median price, double the window length.
|
||||
///
|
||||
/// We additionally +1 so there is a true median.
|
||||
pub const MEDIAN_PRICE_WINDOW_LENGTH: u16 = (2 * ARBITRAGE_TIME) + 1;
|
||||
|
||||
/// Amount of blocks per epoch in the fast-epoch feature that is used in tests.
|
||||
pub const FAST_EPOCH_DURATION: u64 = 2 * MINUTES;
|
||||
|
||||
/// Amount of blocks for the initial period era of the emissions under the fast-epoch feature.
|
||||
pub const FAST_EPOCH_INITIAL_PERIOD: u64 = 2 * FAST_EPOCH_DURATION;
|
||||
/// The maximum amount of key shares per set.
|
||||
pub const MAX_KEY_SHARES_PER_SET: u16 = 150;
|
||||
/// The maximum amount of key shares per set, as an u32.
|
||||
pub const MAX_KEY_SHARES_PER_SET_U32: u32 = MAX_KEY_SHARES_PER_SET as u32;
|
||||
|
||||
66
substrate/primitives/src/crypto.rs
Normal file
66
substrate/primitives/src/crypto.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use zeroize::Zeroize;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use sp_core::{ConstU32, bounded::BoundedVec};
|
||||
|
||||
/// A Ristretto public key.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Public(pub [u8; 32]);
|
||||
impl From<sp_core::sr25519::Public> for Public {
|
||||
fn from(public: sp_core::sr25519::Public) -> Self {
|
||||
Self(public.0)
|
||||
}
|
||||
}
|
||||
impl From<Public> for sp_core::sr25519::Public {
|
||||
fn from(public: Public) -> Self {
|
||||
Self::from_raw(public.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// A sr25519 signature.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Signature(pub [u8; 64]);
|
||||
impl From<sp_core::sr25519::Signature> for Signature {
|
||||
fn from(signature: sp_core::sr25519::Signature) -> Self {
|
||||
Self(signature.0)
|
||||
}
|
||||
}
|
||||
impl From<Signature> for sp_core::sr25519::Signature {
|
||||
fn from(signature: Signature) -> Self {
|
||||
Self::from_raw(signature.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// A key for an external network.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct ExternalKey(
|
||||
#[borsh(
|
||||
serialize_with = "crate::borsh_serialize_bounded_vec",
|
||||
deserialize_with = "crate::borsh_deserialize_bounded_vec"
|
||||
)]
|
||||
pub BoundedVec<u8, ConstU32<{ Self::MAX_LEN }>>,
|
||||
);
|
||||
|
||||
impl Zeroize for ExternalKey {
|
||||
fn zeroize(&mut self) {
|
||||
self.0.as_mut().zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalKey {
|
||||
/// The maximum length for am external key.
|
||||
/*
|
||||
This support keys up to 96 bytes (such as BLS12-381 G2, which is the largest elliptic-curve
|
||||
group element we might reasonably use as a key). This can always be increased if we need to
|
||||
adopt a different cryptosystem (one where verification keys are multiple group elements, or
|
||||
where group elements do exceed 96 bytes, such as RSA).
|
||||
*/
|
||||
pub const MAX_LEN: u32 = 96;
|
||||
}
|
||||
|
||||
/// The key pair for a validator set.
|
||||
///
|
||||
/// This is their Ristretto key, used for publishing data onto Serai, and their key on the external
|
||||
/// network.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct KeyPair(pub Public, pub ExternalKey);
|
||||
@@ -1,19 +0,0 @@
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
|
||||
use crate::{Coin, SubstrateAmount};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct QuotePriceParams {
|
||||
pub coin1: Coin,
|
||||
pub coin2: Coin,
|
||||
pub amount: SubstrateAmount,
|
||||
pub include_fee: bool,
|
||||
pub exact_in: bool,
|
||||
}
|
||||
24
substrate/primitives/src/genesis.rs
Normal file
24
substrate/primitives/src/genesis.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use crate::balance::Amount;
|
||||
|
||||
/// The value of non-Bitcoin externals coins present at genesis, relative to Bitcoin.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct GenesisValues {
|
||||
/// The value of Ether, relative to Bitcoin.
|
||||
pub ether: Amount,
|
||||
/// The value of DAI, relative to Bitcoin.
|
||||
pub dai: Amount,
|
||||
/// The value of Monero, relative to Bitcoin.
|
||||
pub monero: Amount,
|
||||
}
|
||||
|
||||
impl GenesisValues {
|
||||
/// The message for the oraclize_values signature.
|
||||
pub fn oraclize_values_message(&self) -> Vec<u8> {
|
||||
borsh::to_vec(&(b"GenesisLiquidity-oraclize_values", self)).unwrap()
|
||||
}
|
||||
}
|
||||
171
substrate/primitives/src/instructions/in/batch.rs
Normal file
171
substrate/primitives/src/instructions/in/batch.rs
Normal file
@@ -0,0 +1,171 @@
|
||||
use alloc::{vec, vec::Vec};
|
||||
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use borsh::{io, BorshSerialize, BorshDeserialize};
|
||||
|
||||
use crate::{
|
||||
BlockHash, crypto::Signature, network_id::ExternalNetworkId,
|
||||
instructions::InInstructionWithBalance,
|
||||
};
|
||||
|
||||
/*
|
||||
`Batch`s have a size limit we enforce upon deserialization.
|
||||
|
||||
The naive solution would be to deserialize, then serialize, and check the serialized length is
|
||||
less than the maximum. This performs a redundant allocation and is computationally non-trivial.
|
||||
|
||||
The next solution would be to wrap the deserialization with a `Cursor` so one can check the
|
||||
amount read, yet `Cursor` isn't available under no-std.
|
||||
|
||||
We solve this by manually implementing a `Cursor`-equivalent (for our purposes) which let us
|
||||
check the total amount read is `<=` the maximum size.
|
||||
|
||||
The issue is we need every call to `BorshDeserialize::deserialize_reader` to use our custom
|
||||
reader, which requires manually implementing it, which means we can't use the derive macro and
|
||||
can't ensure it follows the borsh specification. We solve this by generating two identical
|
||||
structs, one internal with a derived `BorshDeserialize::deserialize_reader`, one public with a
|
||||
manually implemented `BorshDeserialize::deserialize_reader` wrapping the internal struct's. This
|
||||
lets us ensure the correct reader is used and error if the size limit is hit, while still using
|
||||
a derived `BorshDeserialize` which will definitively be compliant.
|
||||
*/
|
||||
macro_rules! batch_struct {
|
||||
(#[$derive: meta] $pub: vis $name: ident) => {
|
||||
/// A batch of `InInstruction`s to publish onto Serai.
|
||||
#[allow(clippy::needless_pub_self)]
|
||||
#[$derive]
|
||||
$pub struct $name {
|
||||
/// The size this will be once encoded.
|
||||
#[allow(dead_code)] // This is unused for the `BatchDeserialize` instance
|
||||
#[borsh(skip)]
|
||||
encoded_size: usize,
|
||||
|
||||
/// The network this batch of instructions is coming from.
|
||||
network: ExternalNetworkId,
|
||||
/// The ID of this `Batch`.
|
||||
id: u32,
|
||||
/// The hash of the external network's block which produced this `Batch`.
|
||||
external_network_block_hash: BlockHash,
|
||||
/// The instructions to execute.
|
||||
instructions: Vec<InInstructionWithBalance>,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
batch_struct!(#[derive(BorshDeserialize)] pub(self) BatchDeserialize);
|
||||
batch_struct!(#[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize)] pub Batch);
|
||||
|
||||
impl BorshDeserialize for Batch {
|
||||
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
|
||||
// A custom reader which enforces the `Batch`'s max size limit
|
||||
struct SizeLimitReader<'a, R: io::Read> {
|
||||
reader: &'a mut R,
|
||||
read: usize,
|
||||
}
|
||||
impl<R: io::Read> io::Read for SizeLimitReader<'_, R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let read = self.reader.read(buf)?;
|
||||
self.read = self.read.saturating_add(read);
|
||||
if self.read > Batch::MAX_SIZE {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "Batch size exceeded maximum"))?;
|
||||
}
|
||||
Ok(read)
|
||||
}
|
||||
}
|
||||
|
||||
let mut size_limit_reader = SizeLimitReader { reader, read: 0 };
|
||||
let BatchDeserialize {
|
||||
encoded_size: _,
|
||||
network,
|
||||
id,
|
||||
external_network_block_hash,
|
||||
instructions,
|
||||
} = <_>::deserialize_reader(&mut size_limit_reader)?;
|
||||
Ok(Batch {
|
||||
encoded_size: size_limit_reader.read,
|
||||
network,
|
||||
id,
|
||||
external_network_block_hash,
|
||||
instructions,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An error incurred while pushing an instruction onto a `Batch`.
|
||||
pub enum PushInstructionError {
|
||||
/// The Batch's max size was exceeded.
|
||||
MaxSizeExceeded,
|
||||
}
|
||||
|
||||
impl Batch {
|
||||
/// The maximum size of a valid `Batch`'s encoding.
|
||||
const MAX_SIZE: usize = 32_768;
|
||||
|
||||
/// Create a new Batch.
|
||||
pub fn new(network: ExternalNetworkId, id: u32, external_network_block_hash: BlockHash) -> Self {
|
||||
let mut batch =
|
||||
Batch { encoded_size: 0, network, id, external_network_block_hash, instructions: vec![] };
|
||||
batch.encoded_size = borsh::to_vec(&batch).unwrap().len();
|
||||
batch
|
||||
}
|
||||
|
||||
/// Push an `InInstructionWithBalance` onto this `Batch`.
|
||||
pub fn push_instruction(
|
||||
&mut self,
|
||||
instruction: InInstructionWithBalance,
|
||||
) -> Result<(), PushInstructionError> {
|
||||
if (self.encoded_size.saturating_add(borsh::to_vec(&instruction).unwrap().len())) >
|
||||
Self::MAX_SIZE
|
||||
{
|
||||
Err(PushInstructionError::MaxSizeExceeded)?;
|
||||
}
|
||||
self.instructions.push(instruction);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The message to sign when publishing this Batch.
|
||||
pub fn publish_batch_message(&self) -> Vec<u8> {
|
||||
const DST: &[u8] = b"InInstructions-publish_batch";
|
||||
// We don't estimate the size of this Batch, we just reserve a small constant capacity
|
||||
let mut buf = Vec::with_capacity(1024);
|
||||
(DST, self).serialize(&mut buf).unwrap();
|
||||
buf
|
||||
}
|
||||
|
||||
/// The network this batch of instructions is coming from.
|
||||
pub fn network(&self) -> ExternalNetworkId {
|
||||
self.network
|
||||
}
|
||||
|
||||
/// The ID of this `Batch`.
|
||||
pub fn id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// The hash of the external network's block which produced this `Batch`.
|
||||
pub fn external_network_block_hash(&self) -> BlockHash {
|
||||
self.external_network_block_hash
|
||||
}
|
||||
|
||||
/// The instructions within this `Batch`.
|
||||
pub fn instructions(&self) -> &[InInstructionWithBalance] {
|
||||
&self.instructions
|
||||
}
|
||||
}
|
||||
|
||||
/// A signed batch.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct SignedBatch {
|
||||
/// The signed batch.
|
||||
pub batch: Batch,
|
||||
/// The signature.
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Zeroize for SignedBatch {
|
||||
fn zeroize(&mut self) {
|
||||
self.batch.zeroize();
|
||||
self.signature.0.as_mut().zeroize();
|
||||
}
|
||||
}
|
||||
86
substrate/primitives/src/instructions/in/mod.rs
Normal file
86
substrate/primitives/src/instructions/in/mod.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
use zeroize::Zeroize;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use crate::{
|
||||
address::{SeraiAddress, ExternalAddress},
|
||||
balance::{Amount, ExternalBalance, Balance},
|
||||
instructions::OutInstruction,
|
||||
};
|
||||
|
||||
mod batch;
|
||||
pub use batch::*;
|
||||
|
||||
/// The destination for coins.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Destination {
|
||||
/// The Serai address to transfer the coins to.
|
||||
Serai(SeraiAddress),
|
||||
/// Burn the coins with the included `OutInstruction`.
|
||||
Burn(OutInstruction),
|
||||
}
|
||||
|
||||
/// An instruction on how to handle coins in.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub enum InInstruction {
|
||||
/// Add the coins as genesis liquidity.
|
||||
GenesisLiquidity(SeraiAddress),
|
||||
/// Use the coins to swap to staked SRI, pre-economic security.
|
||||
SwapToStakedSri {
|
||||
/// The validator to allocate the stake to.
|
||||
validator: SeraiAddress,
|
||||
/// The minimum amount of staked SRI to swap to.
|
||||
minimum: Amount,
|
||||
},
|
||||
/// Transfer the coins to a Serai address, swapping some for SRI.
|
||||
TransferWithSwap {
|
||||
/// The Serai address to transfer the coins to, after swapping some.
|
||||
to: SeraiAddress,
|
||||
/// The maximum amount of coins to swap for the intended amount of SRI.
|
||||
maximum_swap: Amount,
|
||||
/// The SRI amount to swap some of the coins for.
|
||||
sri: Amount,
|
||||
},
|
||||
/// Transfer the coins to a Serai address.
|
||||
Transfer {
|
||||
/// The Serai address to transfer the coins to.
|
||||
to: SeraiAddress,
|
||||
},
|
||||
/// Swap part of the coins to SRI and add the coins as liquidity.
|
||||
SwapAndAddLiquidity {
|
||||
/// The owner to-be of the added liquidity.
|
||||
owner: SeraiAddress,
|
||||
/// The amount of SRI to add within the liquidity position.
|
||||
sri: Amount,
|
||||
/// The minimum amount of the coin to add as liquidity.
|
||||
minimum_coin: Amount,
|
||||
/// The amount of SRI to swap to and send to the owner to-be to pay for transactions on Serai.
|
||||
sri_for_fees: Amount,
|
||||
},
|
||||
/// Swap the coins.
|
||||
Swap {
|
||||
/// The minimum balance to receive.
|
||||
minimum_out: Balance,
|
||||
/// The destination to transfer the balance to.
|
||||
///
|
||||
/// If `Destination::Burn`, the balance out will be burnt with the included `OutInstruction`.
|
||||
destination: Destination,
|
||||
},
|
||||
}
|
||||
|
||||
/// An instruction on how to handle coins in with the address to return the coins to on error.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct RefundableInInstruction {
|
||||
/// The instruction on how to handle coins in.
|
||||
pub instruction: InInstruction,
|
||||
/// The address to return the coins to on error.
|
||||
pub return_address: Option<ExternalAddress>,
|
||||
}
|
||||
|
||||
/// An instruction on how to handle coins in with the balance to use for the coins in.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct InInstructionWithBalance {
|
||||
/// The instruction on how to handle coins in.
|
||||
pub instruction: OutInstruction,
|
||||
/// The coins in.
|
||||
pub balance: ExternalBalance,
|
||||
}
|
||||
5
substrate/primitives/src/instructions/mod.rs
Normal file
5
substrate/primitives/src/instructions/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod r#in;
|
||||
pub use r#in::{InInstruction, InInstructionWithBalance, PushInstructionError, Batch, SignedBatch};
|
||||
|
||||
mod out;
|
||||
pub use out::{OutInstruction, OutInstructionWithBalance};
|
||||
21
substrate/primitives/src/instructions/out.rs
Normal file
21
substrate/primitives/src/instructions/out.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use crate::{address::ExternalAddress, balance::ExternalBalance};
|
||||
|
||||
/// An instruction on how to transfer coins out.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub enum OutInstruction {
|
||||
/// Transfer to the specified address.
|
||||
Transfer(ExternalAddress),
|
||||
}
|
||||
|
||||
/// An instruction on how to transfer coins out with the balance to use for the transfer out.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct OutInstructionWithBalance {
|
||||
/// The instruction on how to transfer coins out.
|
||||
pub instruction: OutInstruction,
|
||||
/// The balance to use for the transfer out.
|
||||
pub balance: ExternalBalance,
|
||||
}
|
||||
@@ -1,168 +1,79 @@
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate alloc;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
use ::borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
/// Wrappers to implement Borsh on non-Borsh-implementing types.
|
||||
#[doc(hidden)]
|
||||
pub mod sp_borsh;
|
||||
pub(crate) use sp_borsh::*;
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
/// Constants within the Serai protocol.
|
||||
pub mod constants;
|
||||
|
||||
#[cfg(test)]
|
||||
use sp_io::TestExternalities;
|
||||
/// Cryptographic types.
|
||||
pub mod crypto;
|
||||
|
||||
#[cfg(test)]
|
||||
use frame_support::{pallet_prelude::*, Identity, traits::StorageInstance};
|
||||
/// Address types.
|
||||
pub mod address;
|
||||
|
||||
use sp_core::{ConstU32, bounded::BoundedVec};
|
||||
pub use sp_application_crypto as crypto;
|
||||
/// Types for identifying coins.
|
||||
pub mod coin;
|
||||
|
||||
mod amount;
|
||||
pub use amount::*;
|
||||
/// The `Amount`, `ExternalBalance`, and `Balance` types.
|
||||
pub mod balance;
|
||||
|
||||
mod block;
|
||||
pub use block::*;
|
||||
/// Types for genesis.
|
||||
pub mod genesis;
|
||||
|
||||
mod networks;
|
||||
pub use networks::*;
|
||||
/// Types for identifying networks and their properties.
|
||||
pub mod network_id;
|
||||
|
||||
mod balance;
|
||||
pub use balance::*;
|
||||
/// Types for identifying and working with validator sets.
|
||||
pub mod validator_sets;
|
||||
|
||||
mod account;
|
||||
pub use account::*;
|
||||
/// Types for signaling.
|
||||
pub mod signals;
|
||||
|
||||
mod constants;
|
||||
pub use constants::*;
|
||||
/// Instruction types.
|
||||
pub mod instructions;
|
||||
|
||||
mod dex;
|
||||
#[allow(unused_imports)]
|
||||
pub use dex::*;
|
||||
|
||||
pub type BlockNumber = u64;
|
||||
pub type Header = sp_runtime::generic::Header<BlockNumber, sp_runtime::traits::BlakeTwo256>;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
pub fn borsh_serialize_bounded_vec<W: borsh::io::Write, T: BorshSerialize, const B: u32>(
|
||||
bounded: &BoundedVec<T, ConstU32<B>>,
|
||||
writer: &mut W,
|
||||
) -> Result<(), borsh::io::Error> {
|
||||
borsh::BorshSerialize::serialize(bounded.as_slice(), writer)
|
||||
}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
pub fn borsh_deserialize_bounded_vec<R: borsh::io::Read, T: BorshDeserialize, const B: u32>(
|
||||
reader: &mut R,
|
||||
) -> Result<BoundedVec<T, ConstU32<B>>, borsh::io::Error> {
|
||||
let vec: Vec<T> = borsh::BorshDeserialize::deserialize_reader(reader)?;
|
||||
vec.try_into().map_err(|_| borsh::io::Error::other("bound exceeded"))
|
||||
}
|
||||
|
||||
pub const MAX_ADDRESS_LEN: u32 = 512;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct ExternalAddress(
|
||||
#[cfg_attr(
|
||||
feature = "borsh",
|
||||
borsh(
|
||||
serialize_with = "borsh_serialize_bounded_vec",
|
||||
deserialize_with = "borsh_deserialize_bounded_vec"
|
||||
)
|
||||
/// The type used to identify block numbers.
|
||||
///
|
||||
/// A block's number is its zero-indexed position on the list of blocks which form a blockchain.
|
||||
/// For non-linear structures, this would presumably be the zero-indexed position within some
|
||||
/// topological order.
|
||||
#[derive(
|
||||
Clone, Copy, Default, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize,
|
||||
)]
|
||||
BoundedVec<u8, ConstU32<{ MAX_ADDRESS_LEN }>>,
|
||||
);
|
||||
#[cfg(feature = "std")]
|
||||
impl Zeroize for ExternalAddress {
|
||||
fn zeroize(&mut self) {
|
||||
self.0.as_mut().zeroize()
|
||||
pub struct BlockNumber(pub u64);
|
||||
impl From<u64> for BlockNumber {
|
||||
fn from(number: u64) -> BlockNumber {
|
||||
BlockNumber(number)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalAddress {
|
||||
#[cfg(feature = "std")]
|
||||
pub fn new(address: Vec<u8>) -> Result<ExternalAddress, &'static str> {
|
||||
Ok(ExternalAddress(address.try_into().map_err(|_| "address length exceeds {MAX_ADDRESS_LEN}")?))
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn consume(self) -> Vec<u8> {
|
||||
self.0.into_inner()
|
||||
/// The type used to identify block hashes.
|
||||
/*
|
||||
Across all networks, block hashes may not be 32 bytes. There may be a network which targets 256
|
||||
bits of security and accordingly has a 64-byte block hash. Serai only targets a 128-bit security
|
||||
level so this is fine for our use-case. If we do ever see a 64-byte block hash, we can simply
|
||||
hash it into a 32-byte hash or truncate it.
|
||||
*/
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct BlockHash(pub [u8; 32]);
|
||||
impl From<[u8; 32]> for BlockHash {
|
||||
fn from(hash: [u8; 32]) -> BlockHash {
|
||||
BlockHash(hash)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for ExternalAddress {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_ref()
|
||||
impl From<sp_core::H256> for BlockHash {
|
||||
fn from(hash: sp_core::H256) -> BlockHash {
|
||||
BlockHash(hash.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Lexicographically reverses a given byte array.
|
||||
pub fn reverse_lexicographic_order<const N: usize>(bytes: [u8; N]) -> [u8; N] {
|
||||
let mut res = [0u8; N];
|
||||
for (i, byte) in bytes.iter().enumerate() {
|
||||
res[i] = !*byte;
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reverse_lexicographic_order() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
use rand_core::{RngCore, OsRng};
|
||||
|
||||
struct Storage;
|
||||
impl StorageInstance for Storage {
|
||||
fn pallet_prefix() -> &'static str {
|
||||
"LexicographicOrder"
|
||||
}
|
||||
|
||||
const STORAGE_PREFIX: &'static str = "storage";
|
||||
}
|
||||
type Map = StorageMap<Storage, Identity, [u8; 8], (), OptionQuery>;
|
||||
|
||||
struct StorageReverse;
|
||||
impl StorageInstance for StorageReverse {
|
||||
fn pallet_prefix() -> &'static str {
|
||||
"LexicographicOrder"
|
||||
}
|
||||
|
||||
const STORAGE_PREFIX: &'static str = "storagereverse";
|
||||
}
|
||||
type MapReverse = StorageMap<StorageReverse, Identity, [u8; 8], (), OptionQuery>;
|
||||
|
||||
// populate the maps
|
||||
let mut amounts = vec![];
|
||||
for _ in 0 .. 100 {
|
||||
amounts.push(OsRng.next_u64());
|
||||
}
|
||||
|
||||
let mut amounts_sorted = amounts.clone();
|
||||
amounts_sorted.sort();
|
||||
for a in amounts {
|
||||
Map::set(a.to_be_bytes(), Some(()));
|
||||
MapReverse::set(reverse_lexicographic_order(a.to_be_bytes()), Some(()));
|
||||
}
|
||||
|
||||
// retrive back and check whether they are sorted as expected
|
||||
let total_size = amounts_sorted.len();
|
||||
let mut map_iter = Map::iter_keys();
|
||||
let mut reverse_map_iter = MapReverse::iter_keys();
|
||||
for i in 0 .. amounts_sorted.len() {
|
||||
let first = map_iter.next().unwrap();
|
||||
let second = reverse_map_iter.next().unwrap();
|
||||
|
||||
assert_eq!(u64::from_be_bytes(first), amounts_sorted[i]);
|
||||
assert_eq!(
|
||||
u64::from_be_bytes(reverse_lexicographic_order(second)),
|
||||
amounts_sorted[total_size - (i + 1)]
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
124
substrate/primitives/src/network_id.rs
Normal file
124
substrate/primitives/src/network_id.rs
Normal file
@@ -0,0 +1,124 @@
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use borsh::{io, BorshSerialize, BorshDeserialize};
|
||||
|
||||
use crate::coin::{ExternalCoin, Coin};
|
||||
|
||||
/// Identifier for an embedded elliptic curve.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub enum EmbeddedEllipticCurve {
|
||||
/// The Embedwards25519 curve, defined over (embedded into) Ed25519's/Ristretto's scalar field.
|
||||
Embedwards25519,
|
||||
/// The secq256k1 curve, forming a cycle with secp256k1.
|
||||
Secq256k1,
|
||||
}
|
||||
|
||||
/// The type used to identify external networks.
|
||||
///
|
||||
/// This type serializes to a subset of `NetworkId`.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
#[borsh(use_discriminant = true)]
|
||||
#[non_exhaustive]
|
||||
pub enum ExternalNetworkId {
|
||||
/// The Bitcoin network.
|
||||
Bitcoin = 1,
|
||||
/// The Ethereum network.
|
||||
Ethereum = 2,
|
||||
/// The Monero network.
|
||||
Monero = 3,
|
||||
}
|
||||
|
||||
impl ExternalNetworkId {
|
||||
/// All external networks.
|
||||
pub fn all() -> impl Iterator<Item = Self> {
|
||||
[ExternalNetworkId::Bitcoin, ExternalNetworkId::Ethereum, ExternalNetworkId::Monero].into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalNetworkId {
|
||||
/// The embedded elliptic curves actively used for this network.
|
||||
///
|
||||
/// This is guaranteed to return `[Embedwards25519]` or
|
||||
/// `[Embedwards25519, *network specific curve*]`.
|
||||
pub fn embedded_elliptic_curves(&self) -> &'static [EmbeddedEllipticCurve] {
|
||||
match self {
|
||||
// We need to generate a Ristretto key for oraclizing and a Secp256k1 key for the network
|
||||
Self::Bitcoin | Self::Ethereum => {
|
||||
&[EmbeddedEllipticCurve::Embedwards25519, EmbeddedEllipticCurve::Secq256k1]
|
||||
}
|
||||
// Since the oraclizing key curve is the same as the network's curve, we only need it
|
||||
Self::Monero => &[EmbeddedEllipticCurve::Embedwards25519],
|
||||
}
|
||||
}
|
||||
|
||||
/// The coins native to this network.
|
||||
pub fn coins(&self) -> &'static [ExternalCoin] {
|
||||
match self {
|
||||
Self::Bitcoin => &[ExternalCoin::Bitcoin],
|
||||
Self::Ethereum => &[ExternalCoin::Ether, ExternalCoin::Dai],
|
||||
Self::Monero => &[ExternalCoin::Monero],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The type used to identify networks.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize)]
|
||||
pub enum NetworkId {
|
||||
/// The Serai network.
|
||||
Serai,
|
||||
/// An external network.
|
||||
External(ExternalNetworkId),
|
||||
}
|
||||
|
||||
impl BorshSerialize for NetworkId {
|
||||
fn serialize<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
|
||||
match self {
|
||||
Self::Serai => writer.write_all(&[0]),
|
||||
Self::External(external) => external.serialize(writer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BorshDeserialize for NetworkId {
|
||||
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
|
||||
let mut kind = [0xff];
|
||||
reader.read_exact(&mut kind)?;
|
||||
match kind[0] {
|
||||
0 => Ok(Self::Serai),
|
||||
_ => ExternalNetworkId::deserialize_reader(&mut kind.as_slice()).map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkId {
|
||||
/// All networks.
|
||||
pub fn all() -> impl Iterator<Item = Self> {
|
||||
core::iter::once(NetworkId::Serai).chain(ExternalNetworkId::all().map(Into::into))
|
||||
}
|
||||
|
||||
/// The coins native to this network.
|
||||
pub fn coins(self) -> impl Iterator<Item = Coin> {
|
||||
let (coins, external_coins): (&[Coin], &[ExternalCoin]) = match self {
|
||||
NetworkId::Serai => (&[Coin::Serai], &[]),
|
||||
NetworkId::External(ext) => (&[], ext.coins()),
|
||||
};
|
||||
coins.iter().copied().chain(external_coins.iter().copied().map(Into::into))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExternalNetworkId> for NetworkId {
|
||||
fn from(network: ExternalNetworkId) -> Self {
|
||||
NetworkId::External(network)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<NetworkId> for ExternalNetworkId {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(network: NetworkId) -> Result<Self, Self::Error> {
|
||||
match network {
|
||||
NetworkId::Serai => Err(())?,
|
||||
NetworkId::External(ext) => Ok(ext),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,479 +0,0 @@
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use scale::{Decode, Encode, EncodeLike, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use sp_core::{ConstU32, bounded::BoundedVec};
|
||||
use sp_std::{vec, vec::Vec};
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use crate::{borsh_serialize_bounded_vec, borsh_deserialize_bounded_vec};
|
||||
|
||||
/// Identifier for an embedded elliptic curve.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum EmbeddedEllipticCurve {
|
||||
Embedwards25519,
|
||||
Secq256k1,
|
||||
}
|
||||
|
||||
/// The type used to identify external networks.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum ExternalNetworkId {
|
||||
Bitcoin,
|
||||
Ethereum,
|
||||
Monero,
|
||||
}
|
||||
|
||||
impl Encode for ExternalNetworkId {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
match self {
|
||||
ExternalNetworkId::Bitcoin => vec![1],
|
||||
ExternalNetworkId::Ethereum => vec![2],
|
||||
ExternalNetworkId::Monero => vec![3],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode for ExternalNetworkId {
|
||||
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||
let kind = input.read_byte()?;
|
||||
match kind {
|
||||
1 => Ok(Self::Bitcoin),
|
||||
2 => Ok(Self::Ethereum),
|
||||
3 => Ok(Self::Monero),
|
||||
_ => Err(scale::Error::from("invalid format")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MaxEncodedLen for ExternalNetworkId {
|
||||
fn max_encoded_len() -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeLike for ExternalNetworkId {}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshSerialize for ExternalNetworkId {
|
||||
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
writer.write_all(&self.encode())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshDeserialize for ExternalNetworkId {
|
||||
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||
let mut kind = [0; 1];
|
||||
reader.read_exact(&mut kind)?;
|
||||
ExternalNetworkId::decode(&mut kind.as_slice())
|
||||
.map_err(|_| std::io::Error::other("invalid format"))
|
||||
}
|
||||
}
|
||||
|
||||
/// The type used to identify networks.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum NetworkId {
|
||||
Serai,
|
||||
External(ExternalNetworkId),
|
||||
}
|
||||
|
||||
impl Encode for NetworkId {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
match self {
|
||||
NetworkId::Serai => vec![0],
|
||||
NetworkId::External(network) => network.encode(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode for NetworkId {
|
||||
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||
let kind = input.read_byte()?;
|
||||
match kind {
|
||||
0 => Ok(Self::Serai),
|
||||
_ => Ok(ExternalNetworkId::decode(&mut [kind].as_slice())?.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MaxEncodedLen for NetworkId {
|
||||
fn max_encoded_len() -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeLike for NetworkId {}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshSerialize for NetworkId {
|
||||
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
writer.write_all(&self.encode())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshDeserialize for NetworkId {
|
||||
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||
let mut kind = [0; 1];
|
||||
reader.read_exact(&mut kind)?;
|
||||
NetworkId::decode(&mut kind.as_slice()).map_err(|_| std::io::Error::other("invalid format"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalNetworkId {
|
||||
/// The embedded elliptic curve actively used for this network.
|
||||
///
|
||||
/// This is guaranteed to return `[]`, `[Embedwards25519]`, or
|
||||
/// `[Embedwards25519, *network specific curve*]`.
|
||||
pub fn embedded_elliptic_curves(&self) -> &'static [EmbeddedEllipticCurve] {
|
||||
match self {
|
||||
// We need to generate a Ristretto key for oraclizing and a Secp256k1 key for the network
|
||||
Self::Bitcoin | Self::Ethereum => {
|
||||
&[EmbeddedEllipticCurve::Embedwards25519, EmbeddedEllipticCurve::Secq256k1]
|
||||
}
|
||||
// Since the oraclizing key curve is the same as the network's curve, we only need it
|
||||
Self::Monero => &[EmbeddedEllipticCurve::Embedwards25519],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn coins(&self) -> Vec<ExternalCoin> {
|
||||
match self {
|
||||
Self::Bitcoin => vec![ExternalCoin::Bitcoin],
|
||||
Self::Ethereum => vec![ExternalCoin::Ether, ExternalCoin::Dai],
|
||||
Self::Monero => vec![ExternalCoin::Monero],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkId {
|
||||
/// The embedded elliptic curve actively used for this network.
|
||||
///
|
||||
/// This is guaranteed to return `[]`, `[Embedwards25519]`, or
|
||||
/// `[Embedwards25519, *network specific curve*]`.
|
||||
pub fn embedded_elliptic_curves(&self) -> &'static [EmbeddedEllipticCurve] {
|
||||
match self {
|
||||
Self::Serai => &[],
|
||||
Self::External(network) => network.embedded_elliptic_curves(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn coins(&self) -> Vec<Coin> {
|
||||
match self {
|
||||
Self::Serai => vec![Coin::Serai],
|
||||
Self::External(network) => {
|
||||
network.coins().into_iter().map(core::convert::Into::into).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExternalNetworkId> for NetworkId {
|
||||
fn from(network: ExternalNetworkId) -> Self {
|
||||
NetworkId::External(network)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<NetworkId> for ExternalNetworkId {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(network: NetworkId) -> Result<Self, Self::Error> {
|
||||
match network {
|
||||
NetworkId::Serai => Err(())?,
|
||||
NetworkId::External(n) => Ok(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const EXTERNAL_NETWORKS: [ExternalNetworkId; 3] =
|
||||
[ExternalNetworkId::Bitcoin, ExternalNetworkId::Ethereum, ExternalNetworkId::Monero];
|
||||
|
||||
pub const NETWORKS: [NetworkId; 4] = [
|
||||
NetworkId::Serai,
|
||||
NetworkId::External(ExternalNetworkId::Bitcoin),
|
||||
NetworkId::External(ExternalNetworkId::Ethereum),
|
||||
NetworkId::External(ExternalNetworkId::Monero),
|
||||
];
|
||||
|
||||
pub const EXTERNAL_COINS: [ExternalCoin; 4] =
|
||||
[ExternalCoin::Bitcoin, ExternalCoin::Ether, ExternalCoin::Dai, ExternalCoin::Monero];
|
||||
|
||||
pub const COINS: [Coin; 5] = [
|
||||
Coin::Serai,
|
||||
Coin::External(ExternalCoin::Bitcoin),
|
||||
Coin::External(ExternalCoin::Ether),
|
||||
Coin::External(ExternalCoin::Dai),
|
||||
Coin::External(ExternalCoin::Monero),
|
||||
];
|
||||
|
||||
/// The type used to identify external coins.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum ExternalCoin {
|
||||
Bitcoin,
|
||||
Ether,
|
||||
Dai,
|
||||
Monero,
|
||||
}
|
||||
|
||||
impl Encode for ExternalCoin {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
match self {
|
||||
ExternalCoin::Bitcoin => vec![4],
|
||||
ExternalCoin::Ether => vec![5],
|
||||
ExternalCoin::Dai => vec![6],
|
||||
ExternalCoin::Monero => vec![7],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode for ExternalCoin {
|
||||
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||
let kind = input.read_byte()?;
|
||||
match kind {
|
||||
4 => Ok(Self::Bitcoin),
|
||||
5 => Ok(Self::Ether),
|
||||
6 => Ok(Self::Dai),
|
||||
7 => Ok(Self::Monero),
|
||||
_ => Err(scale::Error::from("invalid format")),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl MaxEncodedLen for ExternalCoin {
|
||||
fn max_encoded_len() -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeLike for ExternalCoin {}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshSerialize for ExternalCoin {
|
||||
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
writer.write_all(&self.encode())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshDeserialize for ExternalCoin {
|
||||
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||
let mut kind = [0; 1];
|
||||
reader.read_exact(&mut kind)?;
|
||||
ExternalCoin::decode(&mut kind.as_slice()).map_err(|_| std::io::Error::other("invalid format"))
|
||||
}
|
||||
}
|
||||
|
||||
/// The type used to identify coins.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum Coin {
|
||||
Serai,
|
||||
External(ExternalCoin),
|
||||
}
|
||||
|
||||
impl Encode for Coin {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
match self {
|
||||
Coin::Serai => vec![0],
|
||||
Coin::External(ec) => ec.encode(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decode for Coin {
|
||||
fn decode<I: scale::Input>(input: &mut I) -> Result<Self, scale::Error> {
|
||||
let kind = input.read_byte()?;
|
||||
match kind {
|
||||
0 => Ok(Self::Serai),
|
||||
_ => Ok(ExternalCoin::decode(&mut [kind].as_slice())?.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MaxEncodedLen for Coin {
|
||||
fn max_encoded_len() -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodeLike for Coin {}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshSerialize for Coin {
|
||||
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
writer.write_all(&self.encode())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshDeserialize for Coin {
|
||||
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
|
||||
let mut kind = [0; 1];
|
||||
reader.read_exact(&mut kind)?;
|
||||
Coin::decode(&mut kind.as_slice()).map_err(|_| std::io::Error::other("invalid format"))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExternalCoin> for Coin {
|
||||
fn from(coin: ExternalCoin) -> Self {
|
||||
Coin::External(coin)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Coin> for ExternalCoin {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(coin: Coin) -> Result<Self, Self::Error> {
|
||||
match coin {
|
||||
Coin::Serai => Err(())?,
|
||||
Coin::External(c) => Ok(c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalCoin {
|
||||
pub fn network(&self) -> ExternalNetworkId {
|
||||
match self {
|
||||
ExternalCoin::Bitcoin => ExternalNetworkId::Bitcoin,
|
||||
ExternalCoin::Ether | ExternalCoin::Dai => ExternalNetworkId::Ethereum,
|
||||
ExternalCoin::Monero => ExternalNetworkId::Monero,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
ExternalCoin::Bitcoin => "Bitcoin",
|
||||
ExternalCoin::Ether => "Ether",
|
||||
ExternalCoin::Dai => "Dai Stablecoin",
|
||||
ExternalCoin::Monero => "Monero",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn symbol(&self) -> &'static str {
|
||||
match self {
|
||||
ExternalCoin::Bitcoin => "BTC",
|
||||
ExternalCoin::Ether => "ETH",
|
||||
ExternalCoin::Dai => "DAI",
|
||||
ExternalCoin::Monero => "XMR",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decimals(&self) -> u32 {
|
||||
match self {
|
||||
// Ether and DAI have 18 decimals, yet we only track 8 in order to fit them within u64s
|
||||
ExternalCoin::Bitcoin | ExternalCoin::Ether | ExternalCoin::Dai => 8,
|
||||
ExternalCoin::Monero => 12,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Coin {
|
||||
pub fn native() -> Coin {
|
||||
Coin::Serai
|
||||
}
|
||||
|
||||
pub fn network(&self) -> NetworkId {
|
||||
match self {
|
||||
Coin::Serai => NetworkId::Serai,
|
||||
Coin::External(c) => c.network().into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
Coin::Serai => "Serai",
|
||||
Coin::External(c) => c.name(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn symbol(&self) -> &'static str {
|
||||
match self {
|
||||
Coin::Serai => "SRI",
|
||||
Coin::External(c) => c.symbol(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decimals(&self) -> u32 {
|
||||
match self {
|
||||
Coin::Serai => 8,
|
||||
Coin::External(c) => c.decimals(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_native(&self) -> bool {
|
||||
matches!(self, Coin::Serai)
|
||||
}
|
||||
}
|
||||
|
||||
// Max of 8 coins per network
|
||||
// Since Serai isn't interested in listing tokens, as on-chain DEXs will almost certainly have
|
||||
// more liquidity, the only reason we'd have so many coins from a network is if there's no DEX
|
||||
// on-chain
|
||||
// There's probably no chain with so many *worthwhile* coins and no on-chain DEX
|
||||
// This could probably be just 4, yet 8 is a hedge for the unforeseen
|
||||
// If necessary, this can be increased with a fork
|
||||
pub const MAX_COINS_PER_NETWORK: u32 = 8;
|
||||
|
||||
/// Network definition.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Network {
|
||||
#[cfg_attr(
|
||||
feature = "borsh",
|
||||
borsh(
|
||||
serialize_with = "borsh_serialize_bounded_vec",
|
||||
deserialize_with = "borsh_deserialize_bounded_vec"
|
||||
)
|
||||
)]
|
||||
coins: BoundedVec<Coin, ConstU32<{ MAX_COINS_PER_NETWORK }>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Zeroize for Network {
|
||||
fn zeroize(&mut self) {
|
||||
for coin in self.coins.as_mut() {
|
||||
coin.zeroize();
|
||||
}
|
||||
self.coins.truncate(0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Network {
|
||||
#[cfg(feature = "std")]
|
||||
pub fn new(coins: Vec<Coin>) -> Result<Network, &'static str> {
|
||||
if coins.is_empty() {
|
||||
Err("no coins provided")?;
|
||||
}
|
||||
|
||||
let network = coins[0].network();
|
||||
for coin in coins.iter().skip(1) {
|
||||
if coin.network() != network {
|
||||
Err("coins have different networks")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Network {
|
||||
coins: coins.try_into().map_err(|_| "coins length exceeds {MAX_COINS_PER_NETWORK}")?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn coins(&self) -> &[Coin] {
|
||||
&self.coins
|
||||
}
|
||||
}
|
||||
16
substrate/primitives/src/signals.rs
Normal file
16
substrate/primitives/src/signals.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use zeroize::Zeroize;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use crate::network_id::ExternalNetworkId;
|
||||
|
||||
/// A signal.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Signal {
|
||||
/// A signal to retire the current protocol.
|
||||
Retire {
|
||||
/// The protocol to retire in favor of.
|
||||
in_favor_of: [u8; 32],
|
||||
},
|
||||
/// A signal to halt an external network.
|
||||
Halt(ExternalNetworkId),
|
||||
}
|
||||
37
substrate/primitives/src/sp_borsh.rs
Normal file
37
substrate/primitives/src/sp_borsh.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use borsh::{io::*, BorshSerialize, BorshDeserialize};
|
||||
|
||||
use sp_core::{ConstU32, bounded::BoundedVec};
|
||||
|
||||
// TODO: Don't serialize this as a Vec<u8>. Shorten the length-prefix, technically encoding as an
|
||||
// enum.
|
||||
pub fn borsh_serialize_bitvec<W: Write>(
|
||||
bitvec: &bitvec::vec::BitVec<u8, bitvec::order::Lsb0>,
|
||||
writer: &mut W,
|
||||
) -> Result<()> {
|
||||
let vec: &[u8] = bitvec.as_raw_slice();
|
||||
BorshSerialize::serialize(vec, writer)
|
||||
}
|
||||
|
||||
pub fn borsh_deserialize_bitvec<R: Read>(
|
||||
reader: &mut R,
|
||||
) -> Result<bitvec::vec::BitVec<u8, bitvec::order::Lsb0>> {
|
||||
let bitvec: alloc::vec::Vec<u8> = BorshDeserialize::deserialize_reader(reader)?;
|
||||
Ok(bitvec::vec::BitVec::from_vec(bitvec))
|
||||
}
|
||||
|
||||
type SerializeBoundedVecAs<T> = alloc::vec::Vec<T>;
|
||||
|
||||
pub fn borsh_serialize_bounded_vec<W: Write, T: BorshSerialize, const B: u32>(
|
||||
bounded: &BoundedVec<T, ConstU32<B>>,
|
||||
writer: &mut W,
|
||||
) -> Result<()> {
|
||||
let vec: &SerializeBoundedVecAs<T> = bounded.as_ref();
|
||||
BorshSerialize::serialize(vec, writer)
|
||||
}
|
||||
|
||||
pub fn borsh_deserialize_bounded_vec<R: Read, T: BorshDeserialize, const B: u32>(
|
||||
reader: &mut R,
|
||||
) -> Result<BoundedVec<T, ConstU32<B>>> {
|
||||
let vec: SerializeBoundedVecAs<T> = BorshDeserialize::deserialize_reader(reader)?;
|
||||
vec.try_into().map_err(|_| Error::new(ErrorKind::Other, "bound exceeded"))
|
||||
}
|
||||
76
substrate/primitives/src/validator_sets/mod.rs
Normal file
76
substrate/primitives/src/validator_sets/mod.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
|
||||
use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto};
|
||||
|
||||
use crate::{
|
||||
crypto::{Public, KeyPair},
|
||||
network_id::{ExternalNetworkId, NetworkId},
|
||||
};
|
||||
|
||||
mod slashes;
|
||||
pub use slashes::*;
|
||||
|
||||
/// The type used to identify a specific session of validators.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Session(pub u32);
|
||||
|
||||
/// The type used to identify a specific set of validators for an external network.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct ExternalValidatorSet {
|
||||
/// The network this set of validators are for.
|
||||
pub network: ExternalNetworkId,
|
||||
/// Which session this set of validators is occuring during.
|
||||
pub session: Session,
|
||||
}
|
||||
|
||||
/// The type used to identify a specific set of validators.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct ValidatorSet {
|
||||
/// The network this set of validators are for.
|
||||
pub network: NetworkId,
|
||||
/// Which session this set of validators is occuring during.
|
||||
pub session: Session,
|
||||
}
|
||||
|
||||
impl From<ExternalValidatorSet> for ValidatorSet {
|
||||
fn from(set: ExternalValidatorSet) -> Self {
|
||||
ValidatorSet { network: set.network.into(), session: set.session }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ValidatorSet> for ExternalValidatorSet {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(set: ValidatorSet) -> Result<Self, Self::Error> {
|
||||
set.network.try_into().map(|network| ExternalValidatorSet { network, session: set.session })
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalValidatorSet {
|
||||
/// The MuSig context for this validator set.
|
||||
pub fn musig_context(&self) -> Vec<u8> {
|
||||
borsh::to_vec(&(b"ValidatorSets-musig_key".as_ref(), self)).unwrap()
|
||||
}
|
||||
|
||||
/// The MuSig public key for a validator set.
|
||||
///
|
||||
/// This function panics on invalid input, per the definition of `dkg::musig::musig_key`.
|
||||
pub fn musig_key(&self, set_keys: &[Public]) -> Public {
|
||||
let mut keys = Vec::new();
|
||||
for key in set_keys {
|
||||
keys.push(
|
||||
<Ristretto as Ciphersuite>::read_G::<&[u8]>(&mut key.0.as_ref())
|
||||
.expect("invalid participant"),
|
||||
);
|
||||
}
|
||||
Public(dkg::musig::musig_key::<Ristretto>(&self.musig_context(), &keys).unwrap().to_bytes())
|
||||
}
|
||||
|
||||
/// The message for the `set_keys` signature.
|
||||
pub fn set_keys_message(&self, key_pair: &KeyPair) -> Vec<u8> {
|
||||
borsh::to_vec(&(b"ValidatorSets-set_keys", self, key_pair)).unwrap()
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,25 @@
|
||||
use core::{num::NonZero, time::Duration};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use sp_core::{ConstU32, bounded::BoundedVec};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
use serai_primitives::{TARGET_BLOCK_TIME, Amount};
|
||||
|
||||
use crate::{SESSION_LENGTH, MAX_KEY_SHARES_PER_SET_U32};
|
||||
use crate::{
|
||||
constants::{TARGET_BLOCK_TIME, SESSION_LENGTH, MAX_KEY_SHARES_PER_SET_U32},
|
||||
balance::Amount,
|
||||
};
|
||||
|
||||
/// Each slash point is equivalent to the downtime implied by missing a block proposal.
|
||||
// Takes a NonZero<u16> so that the result is never 0.
|
||||
// Takes a NonZero<u16> so that the result is never 0, making this safe to divide by.
|
||||
fn downtime_per_slash_point(validators: NonZero<u16>) -> Duration {
|
||||
Duration::from_secs(TARGET_BLOCK_TIME) * u32::from(u16::from(validators))
|
||||
TARGET_BLOCK_TIME * u32::from(u16::from(validators))
|
||||
}
|
||||
|
||||
/// A slash for a validator.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)]
|
||||
pub enum Slash {
|
||||
/// The slash points accumulated by this validator.
|
||||
///
|
||||
@@ -46,7 +36,7 @@ pub enum Slash {
|
||||
impl Slash {
|
||||
/// Calculate the penalty which should be applied to the validator.
|
||||
///
|
||||
/// Does not panic, even due to overflows, if `allocated_stake + session_rewards <= u64::MAX`.
|
||||
/// Does not panic, even when compiled with checked arithmetic.
|
||||
pub fn penalty(
|
||||
self,
|
||||
validators: NonZero<u16>,
|
||||
@@ -206,31 +196,34 @@ impl Slash {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct SlashReport(pub BoundedVec<Slash, ConstU32<{ MAX_KEY_SHARES_PER_SET_U32 }>>);
|
||||
/// A report of all slashes incurred for a `ValidatorSet`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct SlashReport(
|
||||
#[borsh(
|
||||
serialize_with = "crate::borsh_serialize_bounded_vec",
|
||||
deserialize_with = "crate::borsh_deserialize_bounded_vec"
|
||||
)]
|
||||
pub BoundedVec<Slash, ConstU32<{ MAX_KEY_SHARES_PER_SET_U32 }>>,
|
||||
);
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshSerialize for SlashReport {
|
||||
fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> borsh::io::Result<()> {
|
||||
BorshSerialize::serialize(self.0.as_slice(), writer)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "borsh")]
|
||||
impl BorshDeserialize for SlashReport {
|
||||
fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> borsh::io::Result<Self> {
|
||||
let slashes = Vec::<Slash>::deserialize_reader(reader)?;
|
||||
slashes
|
||||
.try_into()
|
||||
.map(Self)
|
||||
.map_err(|_| borsh::io::Error::other("length of slash report exceeds max validators"))
|
||||
}
|
||||
/// An error when converting from a `Vec`.
|
||||
pub enum FromVecError {
|
||||
/// The source `Vec` was too long to be converted.
|
||||
TooLong,
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<Slash>> for SlashReport {
|
||||
type Error = &'static str;
|
||||
fn try_from(slashes: Vec<Slash>) -> Result<SlashReport, &'static str> {
|
||||
slashes.try_into().map(Self).map_err(|_| "length of slash report exceeds max validators")
|
||||
type Error = FromVecError;
|
||||
fn try_from(slashes: Vec<Slash>) -> Result<SlashReport, FromVecError> {
|
||||
slashes.try_into().map(Self).map_err(|_| FromVecError::TooLong)
|
||||
}
|
||||
}
|
||||
|
||||
impl zeroize::Zeroize for SlashReport {
|
||||
fn zeroize(&mut self) {
|
||||
for slash in self.0.as_mut() {
|
||||
slash.zeroize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,13 +231,18 @@ impl SlashReport {
|
||||
/// The message to sign when publishing this SlashReport.
|
||||
// This is assumed binding to the ValidatorSet via the key signed with
|
||||
pub fn report_slashes_message(&self) -> Vec<u8> {
|
||||
(b"ValidatorSets-report_slashes", &self.0).encode()
|
||||
const DST: &[u8] = b"ValidatorSets-report_slashes";
|
||||
let mut buf = Vec::with_capacity(
|
||||
DST.len() + core::mem::size_of::<u32>() + (self.0.len() * core::mem::size_of::<Slash>()),
|
||||
);
|
||||
(DST, self).serialize(&mut buf).unwrap();
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_penalty() {
|
||||
for validators in [1, 50, 100, crate::MAX_KEY_SHARES_PER_SET] {
|
||||
for validators in [1, 50, 100, crate::constants::MAX_KEY_SHARES_PER_SET] {
|
||||
let validators = NonZero::new(validators).unwrap();
|
||||
// 12 hours of slash points should only decrease the rewards proportionately
|
||||
let twelve_hours_of_slash_points =
|
||||
@@ -316,11 +314,13 @@ fn test_penalty() {
|
||||
|
||||
#[test]
|
||||
fn no_overflow() {
|
||||
// Test with u16::MAX for validators, maximizing the downtime each slash point represents
|
||||
Slash::Points(u32::MAX).penalty(
|
||||
NonZero::new(u16::MAX).unwrap(),
|
||||
Amount(u64::MAX),
|
||||
Amount(u64::MAX),
|
||||
);
|
||||
|
||||
// Test with 1 for validators, in case validators is inversely correlated
|
||||
Slash::Points(u32::MAX).penalty(NonZero::new(1).unwrap(), Amount(u64::MAX), Amount(u64::MAX));
|
||||
}
|
||||
@@ -49,7 +49,7 @@ frame-executive = { git = "https://github.com/serai-dex/polkadot-sdk", branch =
|
||||
frame-benchmarking = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false, optional = true }
|
||||
|
||||
serai-primitives = { path = "../primitives", default-features = false }
|
||||
serai-abi = { path = "../abi", default-features = false, features = ["serde"] }
|
||||
serai-abi = { path = "../abi", default-features = false }
|
||||
|
||||
pallet-timestamp = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
pallet-authorship = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next", default-features = false }
|
||||
@@ -108,7 +108,6 @@ std = [
|
||||
|
||||
"serai-primitives/std",
|
||||
"serai-abi/std",
|
||||
"serai-abi/serde",
|
||||
|
||||
"pallet-timestamp/std",
|
||||
"pallet-authorship/std",
|
||||
|
||||
@@ -1,17 +1 @@
|
||||
#![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;
|
||||
|
||||
use serai_primitives::ExternalNetworkId;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)]
|
||||
#[cfg_attr(feature = "std", derive(zeroize::Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum SignalId {
|
||||
Retirement([u8; 32]),
|
||||
Halt(ExternalNetworkId),
|
||||
}
|
||||
|
||||
@@ -1,171 +1 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto};
|
||||
|
||||
use scale::{Encode, Decode, MaxEncodedLen};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
#[cfg(feature = "borsh")]
|
||||
use borsh::{BorshSerialize, BorshDeserialize};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use sp_core::{ConstU32, bounded::BoundedVec, sr25519::Public};
|
||||
#[cfg(not(feature = "std"))]
|
||||
use sp_std::vec::Vec;
|
||||
|
||||
use serai_primitives::{ExternalNetworkId, NetworkId};
|
||||
|
||||
mod slash_points;
|
||||
pub use slash_points::*;
|
||||
|
||||
/// The expected duration for a session.
|
||||
// 1 week
|
||||
pub const SESSION_LENGTH: Duration = Duration::from_secs(7 * 24 * 60 * 60);
|
||||
|
||||
/// The maximum length for a key.
|
||||
// Support keys up to 96 bytes (BLS12-381 G2).
|
||||
pub const MAX_KEY_LEN: u32 = 96;
|
||||
|
||||
/// The maximum amount of key shares per set.
|
||||
pub const MAX_KEY_SHARES_PER_SET: u16 = 150;
|
||||
pub const MAX_KEY_SHARES_PER_SET_U32: u32 = MAX_KEY_SHARES_PER_SET as u32;
|
||||
|
||||
/// The type used to identify a specific session of validators.
|
||||
#[derive(
|
||||
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encode, Decode, TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Session(pub u32);
|
||||
|
||||
/// The type used to identify a specific validator set during a specific session.
|
||||
#[derive(
|
||||
Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encode, Decode, TypeInfo, MaxEncodedLen,
|
||||
)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct ValidatorSet {
|
||||
pub session: Session,
|
||||
pub network: NetworkId,
|
||||
}
|
||||
|
||||
/// The type used to identify a specific validator set during a specific session.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "std", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct ExternalValidatorSet {
|
||||
pub session: Session,
|
||||
pub network: ExternalNetworkId,
|
||||
}
|
||||
|
||||
impl From<ExternalValidatorSet> for ValidatorSet {
|
||||
fn from(set: ExternalValidatorSet) -> Self {
|
||||
ValidatorSet { session: set.session, network: set.network.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ValidatorSet> for ExternalValidatorSet {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(set: ValidatorSet) -> Result<Self, Self::Error> {
|
||||
match set.network {
|
||||
NetworkId::Serai => Err(())?,
|
||||
NetworkId::External(network) => Ok(ExternalValidatorSet { session: set.session, network }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The type representing a Key from an external network.
|
||||
pub type ExternalKey = BoundedVec<u8, ConstU32<MAX_KEY_LEN>>;
|
||||
|
||||
/// The key pair for a validator set.
|
||||
///
|
||||
/// This is their Ristretto key, used for publishing data onto Serai, and their key on the external
|
||||
/// network.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)]
|
||||
#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct KeyPair(
|
||||
#[cfg_attr(
|
||||
feature = "borsh",
|
||||
borsh(
|
||||
serialize_with = "serai_primitives::borsh_serialize_public",
|
||||
deserialize_with = "serai_primitives::borsh_deserialize_public"
|
||||
)
|
||||
)]
|
||||
pub Public,
|
||||
#[cfg_attr(
|
||||
feature = "borsh",
|
||||
borsh(
|
||||
serialize_with = "serai_primitives::borsh_serialize_bounded_vec",
|
||||
deserialize_with = "serai_primitives::borsh_deserialize_bounded_vec"
|
||||
)
|
||||
)]
|
||||
pub ExternalKey,
|
||||
);
|
||||
#[cfg(feature = "std")]
|
||||
impl Zeroize for KeyPair {
|
||||
fn zeroize(&mut self) {
|
||||
self.0 .0.zeroize();
|
||||
self.1.as_mut().zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
/// The MuSig context for a validator set.
|
||||
pub fn musig_context(set: ValidatorSet) -> Vec<u8> {
|
||||
(b"ValidatorSets-musig_key".as_ref(), set).encode()
|
||||
}
|
||||
|
||||
/// The MuSig public key for a validator set.
|
||||
///
|
||||
/// This function panics on invalid input, per the definition of `dkg::musig::musig_key`.
|
||||
pub fn musig_key(set: ValidatorSet, set_keys: &[Public]) -> Public {
|
||||
let mut keys = Vec::new();
|
||||
for key in set_keys {
|
||||
keys.push(
|
||||
<Ristretto as Ciphersuite>::read_G::<&[u8]>(&mut key.0.as_ref())
|
||||
.expect("invalid participant"),
|
||||
);
|
||||
}
|
||||
Public(dkg::musig::musig_key::<Ristretto>(&musig_context(set), &keys).unwrap().to_bytes())
|
||||
}
|
||||
|
||||
/// The message for the `set_keys` signature.
|
||||
pub fn set_keys_message(set: &ExternalValidatorSet, key_pair: &KeyPair) -> Vec<u8> {
|
||||
(b"ValidatorSets-set_keys", set, key_pair).encode()
|
||||
}
|
||||
|
||||
/// For a set of validators whose key shares may exceed the maximum, reduce until they equal the
|
||||
/// maximum.
|
||||
///
|
||||
/// Reduction occurs by reducing each validator in a reverse round-robin.
|
||||
pub fn amortize_excess_key_shares(validators: &mut [(Public, u64)]) {
|
||||
let total_key_shares = validators.iter().map(|(_, shares)| shares).sum::<u64>();
|
||||
for i in 0 .. usize::try_from(total_key_shares.saturating_sub(u64::from(MAX_KEY_SHARES_PER_SET)))
|
||||
.unwrap()
|
||||
{
|
||||
validators[validators.len() - ((i % validators.len()) + 1)].1 -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the post-amortization key shares for the top validator.
|
||||
///
|
||||
/// Panics when `validators == 0`.
|
||||
pub fn post_amortization_key_shares_for_top_validator(
|
||||
validators: usize,
|
||||
top: u64,
|
||||
key_shares: u64,
|
||||
) -> u64 {
|
||||
top -
|
||||
(key_shares.saturating_sub(MAX_KEY_SHARES_PER_SET.into()) /
|
||||
u64::try_from(validators).unwrap())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user